@acta-markets/ts-sdk 0.0.4-beta → 0.0.6-beta
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 +4 -1
- package/dist/cjs/events.test.js +6 -0
- package/dist/cjs/generated/types/actaEvent.js +6 -0
- package/dist/cjs/idl/acta_contract.json +17 -0
- package/dist/cjs/idl/hash.js +1 -1
- package/dist/cjs/ws/client.js +109 -14
- package/dist/cjs/ws/client.test.js +199 -3
- package/dist/cjs/ws/discovery.js +2 -0
- package/dist/cjs/ws/wirePolicy.js +16 -0
- package/dist/cjs/ws/wirePolicy.test.js +22 -0
- package/dist/events.test.js +6 -0
- package/dist/generated/types/actaEvent.d.ts +6 -0
- package/dist/generated/types/actaEvent.js +6 -0
- package/dist/idl/acta_contract.json +17 -0
- package/dist/idl/hash.d.ts +1 -1
- package/dist/idl/hash.js +1 -1
- package/dist/ws/client.d.ts +18 -13
- package/dist/ws/client.js +110 -15
- package/dist/ws/client.test.js +199 -3
- package/dist/ws/discovery.js +2 -0
- package/dist/ws/types.d.ts +70 -5
- package/dist/ws/wirePolicy.d.ts +6 -0
- package/dist/ws/wirePolicy.js +15 -0
- package/dist/ws/wirePolicy.test.d.ts +1 -0
- package/dist/ws/wirePolicy.test.js +20 -0
- package/package.json +1 -1
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const wirePolicy_1 = require("./wirePolicy");
|
|
4
|
+
describe("validateQuantityBySizeRule", () => {
|
|
5
|
+
const rule = {
|
|
6
|
+
min_size: 2_000_000_000,
|
|
7
|
+
max_size: 10_000_000_000,
|
|
8
|
+
step: 1_000_000_000,
|
|
9
|
+
};
|
|
10
|
+
it("accepts a valid quantity", () => {
|
|
11
|
+
expect(() => (0, wirePolicy_1.validateQuantityBySizeRule)(6_000_000_000, rule)).not.toThrow();
|
|
12
|
+
});
|
|
13
|
+
it("rejects quantity below min", () => {
|
|
14
|
+
expect(() => (0, wirePolicy_1.validateQuantityBySizeRule)(1_000_000_000, rule)).toThrow("must be within");
|
|
15
|
+
});
|
|
16
|
+
it("rejects quantity above max", () => {
|
|
17
|
+
expect(() => (0, wirePolicy_1.validateQuantityBySizeRule)(11_000_000_000, rule)).toThrow("must be within");
|
|
18
|
+
});
|
|
19
|
+
it("rejects quantity with invalid step", () => {
|
|
20
|
+
expect(() => (0, wirePolicy_1.validateQuantityBySizeRule)(2_500_000_000, rule)).toThrow("(quantity - min_size) % step == 0");
|
|
21
|
+
});
|
|
22
|
+
});
|
package/dist/events.test.js
CHANGED
|
@@ -182,6 +182,8 @@ describe("events parsing", () => {
|
|
|
182
182
|
Buffer.from(pk(3)),
|
|
183
183
|
u64(777),
|
|
184
184
|
Buffer.from([1]), // is_put
|
|
185
|
+
Buffer.from([6]), // underlying_decimals
|
|
186
|
+
Buffer.from([9]), // quote_decimals
|
|
185
187
|
]));
|
|
186
188
|
const d = decodeActaEventLine(line);
|
|
187
189
|
expect(d.kind).toBe(EventKind.CreateMarket);
|
|
@@ -192,6 +194,8 @@ describe("events parsing", () => {
|
|
|
192
194
|
expect(d.event.quoteMint).toBe(addr(3));
|
|
193
195
|
expect(d.event.expiryTs).toBe(777n);
|
|
194
196
|
expect(d.event.isPut).toBe(1);
|
|
197
|
+
expect(d.event.underlyingDecimals).toBe(6);
|
|
198
|
+
expect(d.event.quoteDecimals).toBe(9);
|
|
195
199
|
}
|
|
196
200
|
}
|
|
197
201
|
// 9: FinalizeMarket
|
|
@@ -213,6 +217,7 @@ describe("events parsing", () => {
|
|
|
213
217
|
u64(222),
|
|
214
218
|
Buffer.from([1]),
|
|
215
219
|
Buffer.from(pk(3)),
|
|
220
|
+
Buffer.from(pk(9)),
|
|
216
221
|
]));
|
|
217
222
|
const d = decodeActaEventLine(line);
|
|
218
223
|
expect(d.kind).toBe(EventKind.CreateOracle);
|
|
@@ -223,6 +228,7 @@ describe("events parsing", () => {
|
|
|
223
228
|
expect(d.event.expiryTs).toBe(222n);
|
|
224
229
|
expect(d.event.oracleType).toBe(1);
|
|
225
230
|
expect(d.event.authority).toBe(addr(3));
|
|
231
|
+
expect(Buffer.from(d.event.feedId)).toEqual(Buffer.from(pk(9)));
|
|
226
232
|
}
|
|
227
233
|
}
|
|
228
234
|
// 15: UpdateOraclePrice
|
|
@@ -55,6 +55,8 @@ export type ActaEvent = {
|
|
|
55
55
|
quoteMint: Address;
|
|
56
56
|
expiryTs: bigint;
|
|
57
57
|
isPut: number;
|
|
58
|
+
underlyingDecimals: number;
|
|
59
|
+
quoteDecimals: number;
|
|
58
60
|
} | {
|
|
59
61
|
__kind: "FinalizeMarket";
|
|
60
62
|
marketPda: Address;
|
|
@@ -95,6 +97,7 @@ export type ActaEvent = {
|
|
|
95
97
|
expiryTs: bigint;
|
|
96
98
|
oracleType: number;
|
|
97
99
|
authority: Address;
|
|
100
|
+
feedId: ReadonlyUint8Array;
|
|
98
101
|
} | {
|
|
99
102
|
__kind: "UpdateOraclePrice";
|
|
100
103
|
oraclePda: Address;
|
|
@@ -163,6 +166,8 @@ export type ActaEventArgs = {
|
|
|
163
166
|
quoteMint: Address;
|
|
164
167
|
expiryTs: number | bigint;
|
|
165
168
|
isPut: number;
|
|
169
|
+
underlyingDecimals: number;
|
|
170
|
+
quoteDecimals: number;
|
|
166
171
|
} | {
|
|
167
172
|
__kind: "FinalizeMarket";
|
|
168
173
|
marketPda: Address;
|
|
@@ -203,6 +208,7 @@ export type ActaEventArgs = {
|
|
|
203
208
|
expiryTs: number | bigint;
|
|
204
209
|
oracleType: number;
|
|
205
210
|
authority: Address;
|
|
211
|
+
feedId: ReadonlyUint8Array;
|
|
206
212
|
} | {
|
|
207
213
|
__kind: "UpdateOraclePrice";
|
|
208
214
|
oraclePda: Address;
|
|
@@ -82,6 +82,8 @@ export function getActaEventEncoder() {
|
|
|
82
82
|
["quoteMint", getAddressEncoder()],
|
|
83
83
|
["expiryTs", getU64Encoder()],
|
|
84
84
|
["isPut", getU8Encoder()],
|
|
85
|
+
["underlyingDecimals", getU8Encoder()],
|
|
86
|
+
["quoteDecimals", getU8Encoder()],
|
|
85
87
|
]),
|
|
86
88
|
],
|
|
87
89
|
[
|
|
@@ -135,6 +137,7 @@ export function getActaEventEncoder() {
|
|
|
135
137
|
["expiryTs", getU64Encoder()],
|
|
136
138
|
["oracleType", getU8Encoder()],
|
|
137
139
|
["authority", getAddressEncoder()],
|
|
140
|
+
["feedId", fixEncoderSize(getBytesEncoder(), 32)],
|
|
138
141
|
]),
|
|
139
142
|
],
|
|
140
143
|
[
|
|
@@ -240,6 +243,8 @@ export function getActaEventDecoder() {
|
|
|
240
243
|
["quoteMint", getAddressDecoder()],
|
|
241
244
|
["expiryTs", getU64Decoder()],
|
|
242
245
|
["isPut", getU8Decoder()],
|
|
246
|
+
["underlyingDecimals", getU8Decoder()],
|
|
247
|
+
["quoteDecimals", getU8Decoder()],
|
|
243
248
|
]),
|
|
244
249
|
],
|
|
245
250
|
[
|
|
@@ -293,6 +298,7 @@ export function getActaEventDecoder() {
|
|
|
293
298
|
["expiryTs", getU64Decoder()],
|
|
294
299
|
["oracleType", getU8Decoder()],
|
|
295
300
|
["authority", getAddressDecoder()],
|
|
301
|
+
["feedId", fixDecoderSize(getBytesDecoder(), 32)],
|
|
296
302
|
]),
|
|
297
303
|
],
|
|
298
304
|
[
|
|
@@ -1883,6 +1883,14 @@
|
|
|
1883
1883
|
{
|
|
1884
1884
|
"name": "is_put",
|
|
1885
1885
|
"type": "u8"
|
|
1886
|
+
},
|
|
1887
|
+
{
|
|
1888
|
+
"name": "underlying_decimals",
|
|
1889
|
+
"type": "u8"
|
|
1890
|
+
},
|
|
1891
|
+
{
|
|
1892
|
+
"name": "quote_decimals",
|
|
1893
|
+
"type": "u8"
|
|
1886
1894
|
}
|
|
1887
1895
|
]
|
|
1888
1896
|
},
|
|
@@ -2030,6 +2038,15 @@
|
|
|
2030
2038
|
{
|
|
2031
2039
|
"name": "authority",
|
|
2032
2040
|
"type": "publicKey"
|
|
2041
|
+
},
|
|
2042
|
+
{
|
|
2043
|
+
"name": "feed_id",
|
|
2044
|
+
"type": {
|
|
2045
|
+
"array": [
|
|
2046
|
+
"u8",
|
|
2047
|
+
32
|
|
2048
|
+
]
|
|
2049
|
+
}
|
|
2033
2050
|
}
|
|
2034
2051
|
]
|
|
2035
2052
|
},
|
package/dist/idl/hash.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const ACTA_IDL_SHA256 = "
|
|
1
|
+
export declare const ACTA_IDL_SHA256 = "704677f7071ecbe98f442fb62468d882329b906950a707fc47aad0f38683636f";
|
package/dist/idl/hash.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const ACTA_IDL_SHA256 = "
|
|
1
|
+
export const ACTA_IDL_SHA256 = "704677f7071ecbe98f442fb62468d882329b906950a707fc47aad0f38683636f";
|
package/dist/ws/client.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import type { AuthProvider } from "./auth";
|
|
3
3
|
import type { SignerLike } from "../chain/orders";
|
|
4
4
|
import type { Address } from "@solana/addresses";
|
|
5
|
-
import type { ActiveRfqInfo, ChainEventMessage, GlobalStats, MarketDescriptorInfo, MarketInfo, MyActiveRfqInfo, MyActiveRfqsMessage, OrderStatusMessage, PositionInfo, QuoteAcknowledgedMessage, QuoteBestStatusMessage, QuoteCancelledMessage, QuoteMessage, QuoteRefreshRequestedMessage, QuoteOutbidMessage, QuoteReceivedMessage, QuoteSelectedMessage, QuotesUpdateMessage, RfqBroadcastMessage, RfqClosedMessage, RfqCreatedMessage, RfqRequestMessage, RfqAvailableAgainMessage, QuoteExpiredMessage, QuoteFilledMessage, IndicativePricesMessage, IndicativePricesRequestMessage, IndicativePricesResponseMessage, GetIndicativePricesMessage, ServerMessage, SnapshotMessage, StatsDelta, SubscriptionsMessage, TokenInfo, TradeInfo, UuidString, VersionMismatchMessage, WelcomeMessage, WsChannel } from "./types";
|
|
5
|
+
import type { ActiveRfqInfo, ChainEventMessage, GlobalStats, MarketDescriptorInfo, MarketInfo, MyActiveRfqInfo, MyActiveRfqsMessage, OrderStatusMessage, PositionInfo, QuoteAcknowledgedMessage, QuoteBestStatusMessage, QuoteCancelledMessage, QuoteMessage, QuoteRefreshRequestedMessage, QuoteOutbidMessage, QuoteReceivedMessage, QuoteSelectedMessage, QuotesUpdateMessage, RfqBroadcastMessage, RfqClosedMessage, RfqCreatedMessage, RfqRequestMessage, RfqAvailableAgainMessage, QuoteExpiredMessage, QuoteFilledMessage, IndicativePricesMessage, IndicativePricesRequestMessage, IndicativePricesResponseMessage, GetIndicativePricesMessage, RequestId, ServerMessage, SnapshotMessage, StatsDelta, SubscriptionsMessage, TokenInfo, TradeInfo, UuidString, VersionMismatchMessage, WelcomeMessage, WsChannel } from "./types";
|
|
6
6
|
export type ConnectionState = "disconnected" | "connecting" | "authenticating" | "authenticated" | "error";
|
|
7
7
|
export type ClientRole = "taker" | "maker";
|
|
8
8
|
export type PendingMessagesOverflowPolicy = "drop_oldest" | "drop_newest" | "throw";
|
|
@@ -57,7 +57,8 @@ export type ActaWsClientEvents = {
|
|
|
57
57
|
welcome: (msg: WelcomeMessage) => void;
|
|
58
58
|
versionMismatch: (msg: VersionMismatchMessage) => void;
|
|
59
59
|
authenticated: (sessionId: string, expiresAt: number | null) => void;
|
|
60
|
-
authError: (reason: string) => void;
|
|
60
|
+
authError: (reason: string, message?: string) => void;
|
|
61
|
+
logoutSuccess: () => void;
|
|
61
62
|
disconnected: (code: number, reason: string) => void;
|
|
62
63
|
error: (error: Error) => void;
|
|
63
64
|
stateChange: (state: ConnectionState) => void;
|
|
@@ -151,6 +152,7 @@ export declare class ActaWsClient extends TypedEventEmitter<ActaWsClientEvents>
|
|
|
151
152
|
private pendingResumeSessionId;
|
|
152
153
|
private connectionState;
|
|
153
154
|
private sessionId;
|
|
155
|
+
private lastAuthSessionId;
|
|
154
156
|
private helloSent;
|
|
155
157
|
private welcomeReceived;
|
|
156
158
|
private pendingMessages;
|
|
@@ -161,6 +163,7 @@ export declare class ActaWsClient extends TypedEventEmitter<ActaWsClientEvents>
|
|
|
161
163
|
private subscribedChannels;
|
|
162
164
|
private subscribedMarkets;
|
|
163
165
|
private hasMarketScope;
|
|
166
|
+
private marketDescriptorsByMarket;
|
|
164
167
|
readonly state: ClientState;
|
|
165
168
|
constructor(options: ActaWsClientOptions);
|
|
166
169
|
connectAnonymous(): void;
|
|
@@ -195,23 +198,24 @@ export declare class ActaWsClient extends TypedEventEmitter<ActaWsClientEvents>
|
|
|
195
198
|
orderIdHex: string;
|
|
196
199
|
txBase64: string;
|
|
197
200
|
}): Promise<void>;
|
|
198
|
-
getPositions():
|
|
199
|
-
getMarkets():
|
|
201
|
+
getPositions(): RequestId;
|
|
202
|
+
getMarkets(): RequestId;
|
|
200
203
|
getMarketDescriptors(args?: {
|
|
201
204
|
active_only?: boolean;
|
|
202
|
-
}):
|
|
205
|
+
}): RequestId;
|
|
203
206
|
getExpiries(args?: {
|
|
204
207
|
underlying_mint?: Address<string>;
|
|
205
208
|
quote_mint?: Address<string>;
|
|
206
209
|
is_put?: boolean | null;
|
|
207
|
-
}):
|
|
210
|
+
}): RequestId;
|
|
208
211
|
getTokens(args?: {
|
|
209
212
|
active_only?: boolean;
|
|
210
|
-
}):
|
|
211
|
-
getMyActiveRfqs():
|
|
212
|
-
getActiveRfqs():
|
|
213
|
-
|
|
214
|
-
|
|
213
|
+
}): RequestId;
|
|
214
|
+
getMyActiveRfqs(): RequestId;
|
|
215
|
+
getActiveRfqs(): RequestId;
|
|
216
|
+
logout(): void;
|
|
217
|
+
getOrderStatus(orderIdHex: string): RequestId;
|
|
218
|
+
cancelRfq(rfqId: string): RequestId;
|
|
215
219
|
submitQuote(quote: QuoteMessage): void;
|
|
216
220
|
/**
|
|
217
221
|
* Convenience: sign 32-byte `orderId` and send `Quote`.
|
|
@@ -228,7 +232,7 @@ export declare class ActaWsClient extends TypedEventEmitter<ActaWsClientEvents>
|
|
|
228
232
|
orderId: Uint8Array;
|
|
229
233
|
makerSigner: SignerLike;
|
|
230
234
|
}): Promise<void>;
|
|
231
|
-
cancelQuote(rfqId: string):
|
|
235
|
+
cancelQuote(rfqId: string): RequestId;
|
|
232
236
|
subscribe(channels: WsChannel[], markets?: string[]): void;
|
|
233
237
|
unsubscribe(channels: WsChannel[]): void;
|
|
234
238
|
ping(): void;
|
|
@@ -236,7 +240,7 @@ export declare class ActaWsClient extends TypedEventEmitter<ActaWsClientEvents>
|
|
|
236
240
|
private doConnect;
|
|
237
241
|
private handleMessage;
|
|
238
242
|
/** Taker-only: request current indicative prices for a market + position_type. */
|
|
239
|
-
getIndicativePrices(req: GetIndicativePricesMessage):
|
|
243
|
+
getIndicativePrices(req: Omit<GetIndicativePricesMessage, "request_id">): RequestId;
|
|
240
244
|
/** Maker-only: respond to an indicative request (unsigned, non-binding). */
|
|
241
245
|
sendIndicativePricesResponse(resp: IndicativePricesResponseMessage): void;
|
|
242
246
|
private handleAuthRequest;
|
|
@@ -257,6 +261,7 @@ export declare class ActaWsClient extends TypedEventEmitter<ActaWsClientEvents>
|
|
|
257
261
|
private handlePositionUpdated;
|
|
258
262
|
private handleChainEvent;
|
|
259
263
|
private send;
|
|
264
|
+
private nextRequestId;
|
|
260
265
|
private ensureAuthenticated;
|
|
261
266
|
private setConnectionState;
|
|
262
267
|
private startPingInterval;
|
package/dist/ws/client.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** Acta WebSocket client (rfq-server). */
|
|
2
2
|
import { buildSignedQuoteMessage, buildAcceptQuoteMessage } from "./flows";
|
|
3
|
-
import { assertWsU64Safe } from "./wirePolicy";
|
|
3
|
+
import { assertWsU64Safe, validateQuantityBySizeRule } from "./wirePolicy";
|
|
4
4
|
function formatServerError(error) {
|
|
5
5
|
if (error.type === "generic") {
|
|
6
6
|
return `${error.data.code}: ${error.data.message}`;
|
|
@@ -70,6 +70,21 @@ function getCloseInfo(ev) {
|
|
|
70
70
|
reason: typeof rec.reason === "string" ? rec.reason : undefined,
|
|
71
71
|
};
|
|
72
72
|
}
|
|
73
|
+
function generateRequestId() {
|
|
74
|
+
const cryptoApi = globalThis.crypto;
|
|
75
|
+
if (cryptoApi?.randomUUID) {
|
|
76
|
+
return cryptoApi.randomUUID();
|
|
77
|
+
}
|
|
78
|
+
if (cryptoApi?.getRandomValues) {
|
|
79
|
+
const bytes = cryptoApi.getRandomValues(new Uint8Array(16));
|
|
80
|
+
// RFC4122 v4 bits: version=0100, variant=10xx.
|
|
81
|
+
bytes[6] = (bytes[6] & 0x0f) | 0x40;
|
|
82
|
+
bytes[8] = (bytes[8] & 0x3f) | 0x80;
|
|
83
|
+
const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
84
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
85
|
+
}
|
|
86
|
+
return `req-${Date.now()}-${Math.random().toString(16).slice(2, 10)}`;
|
|
87
|
+
}
|
|
73
88
|
export class ActaWsClient extends TypedEventEmitter {
|
|
74
89
|
ws = null;
|
|
75
90
|
options;
|
|
@@ -79,6 +94,7 @@ export class ActaWsClient extends TypedEventEmitter {
|
|
|
79
94
|
pendingResumeSessionId = null;
|
|
80
95
|
connectionState = "disconnected";
|
|
81
96
|
sessionId = null;
|
|
97
|
+
lastAuthSessionId = null;
|
|
82
98
|
helloSent = false;
|
|
83
99
|
welcomeReceived = false;
|
|
84
100
|
pendingMessages = [];
|
|
@@ -89,6 +105,7 @@ export class ActaWsClient extends TypedEventEmitter {
|
|
|
89
105
|
subscribedChannels = new Set(["rfqs"]);
|
|
90
106
|
subscribedMarkets = new Set();
|
|
91
107
|
hasMarketScope = false;
|
|
108
|
+
marketDescriptorsByMarket = new Map();
|
|
92
109
|
state = {
|
|
93
110
|
stats: null,
|
|
94
111
|
activeRfqs: new Map(),
|
|
@@ -121,6 +138,7 @@ export class ActaWsClient extends TypedEventEmitter {
|
|
|
121
138
|
this.authProvider = null;
|
|
122
139
|
this.authRequested = false;
|
|
123
140
|
this.pendingResumeSessionId = null;
|
|
141
|
+
this.lastAuthSessionId = null;
|
|
124
142
|
this.shouldReconnect = this.options.autoReconnect;
|
|
125
143
|
this.doConnect();
|
|
126
144
|
}
|
|
@@ -176,6 +194,13 @@ export class ActaWsClient extends TypedEventEmitter {
|
|
|
176
194
|
}
|
|
177
195
|
async createRfq(request) {
|
|
178
196
|
this.ensureAuthenticated();
|
|
197
|
+
assertWsU64Safe(request.strike, "strike");
|
|
198
|
+
assertWsU64Safe(request.quantity, "quantity");
|
|
199
|
+
const marketDescriptor = this.marketDescriptorsByMarket.get(request.market);
|
|
200
|
+
if (!marketDescriptor) {
|
|
201
|
+
throw new Error(`Missing market descriptor for market=${request.market}; call getMarketDescriptors() before createRfq().`);
|
|
202
|
+
}
|
|
203
|
+
validateQuantityBySizeRule(request.quantity, marketDescriptor.size_rule);
|
|
179
204
|
this.send({
|
|
180
205
|
type: "RfqRequest",
|
|
181
206
|
data: {
|
|
@@ -220,47 +245,89 @@ export class ActaWsClient extends TypedEventEmitter {
|
|
|
220
245
|
}
|
|
221
246
|
getPositions() {
|
|
222
247
|
this.ensureAuthenticated();
|
|
223
|
-
this.
|
|
248
|
+
const requestId = this.nextRequestId();
|
|
249
|
+
this.send({
|
|
250
|
+
type: "GetPositions",
|
|
251
|
+
data: { request_id: requestId },
|
|
252
|
+
});
|
|
253
|
+
return requestId;
|
|
224
254
|
}
|
|
225
255
|
getMarkets() {
|
|
226
|
-
this.
|
|
256
|
+
const requestId = this.nextRequestId();
|
|
257
|
+
this.send({
|
|
258
|
+
type: "GetMarkets",
|
|
259
|
+
data: { request_id: requestId },
|
|
260
|
+
});
|
|
261
|
+
return requestId;
|
|
227
262
|
}
|
|
228
263
|
getMarketDescriptors(args) {
|
|
264
|
+
const requestId = this.nextRequestId();
|
|
229
265
|
const data = {
|
|
266
|
+
request_id: requestId,
|
|
230
267
|
active_only: args?.active_only ?? true,
|
|
231
268
|
};
|
|
232
269
|
this.send({ type: "GetMarketDescriptors", data });
|
|
270
|
+
return requestId;
|
|
233
271
|
}
|
|
234
272
|
getExpiries(args) {
|
|
273
|
+
const requestId = this.nextRequestId();
|
|
235
274
|
this.send({
|
|
236
275
|
type: "GetExpiries",
|
|
237
276
|
data: {
|
|
277
|
+
request_id: requestId,
|
|
238
278
|
underlying_mint: args?.underlying_mint,
|
|
239
279
|
quote_mint: args?.quote_mint,
|
|
240
280
|
is_put: args?.is_put ?? null,
|
|
241
281
|
},
|
|
242
282
|
});
|
|
283
|
+
return requestId;
|
|
243
284
|
}
|
|
244
285
|
getTokens(args) {
|
|
286
|
+
const requestId = this.nextRequestId();
|
|
245
287
|
const data = {
|
|
288
|
+
request_id: requestId,
|
|
246
289
|
active_only: args?.active_only ?? true,
|
|
247
290
|
};
|
|
248
291
|
this.send({ type: "GetTokens", data });
|
|
292
|
+
return requestId;
|
|
249
293
|
}
|
|
250
294
|
getMyActiveRfqs() {
|
|
251
295
|
this.ensureAuthenticated();
|
|
252
|
-
this.
|
|
296
|
+
const requestId = this.nextRequestId();
|
|
297
|
+
this.send({
|
|
298
|
+
type: "GetMyActiveRfqs",
|
|
299
|
+
data: { request_id: requestId },
|
|
300
|
+
});
|
|
301
|
+
return requestId;
|
|
253
302
|
}
|
|
254
303
|
getActiveRfqs() {
|
|
255
|
-
this.
|
|
304
|
+
const requestId = this.nextRequestId();
|
|
305
|
+
this.send({
|
|
306
|
+
type: "GetActiveRfqs",
|
|
307
|
+
data: { request_id: requestId },
|
|
308
|
+
});
|
|
309
|
+
return requestId;
|
|
310
|
+
}
|
|
311
|
+
logout() {
|
|
312
|
+
this.send({ type: "Logout" });
|
|
256
313
|
}
|
|
257
314
|
getOrderStatus(orderIdHex) {
|
|
258
315
|
this.ensureAuthenticated();
|
|
259
|
-
this.
|
|
316
|
+
const requestId = this.nextRequestId();
|
|
317
|
+
this.send({
|
|
318
|
+
type: "GetOrderStatus",
|
|
319
|
+
data: { request_id: requestId, order_id: orderIdHex },
|
|
320
|
+
});
|
|
321
|
+
return requestId;
|
|
260
322
|
}
|
|
261
323
|
cancelRfq(rfqId) {
|
|
262
324
|
this.ensureAuthenticated();
|
|
263
|
-
this.
|
|
325
|
+
const requestId = this.nextRequestId();
|
|
326
|
+
this.send({
|
|
327
|
+
type: "CancelRfq",
|
|
328
|
+
data: { rfq_id: rfqId, request_id: requestId },
|
|
329
|
+
});
|
|
330
|
+
return requestId;
|
|
264
331
|
}
|
|
265
332
|
submitQuote(quote) {
|
|
266
333
|
this.ensureAuthenticated();
|
|
@@ -290,7 +357,12 @@ export class ActaWsClient extends TypedEventEmitter {
|
|
|
290
357
|
}
|
|
291
358
|
cancelQuote(rfqId) {
|
|
292
359
|
this.ensureAuthenticated();
|
|
293
|
-
this.
|
|
360
|
+
const requestId = this.nextRequestId();
|
|
361
|
+
this.send({
|
|
362
|
+
type: "CancelQuote",
|
|
363
|
+
data: { rfq_id: rfqId, request_id: requestId },
|
|
364
|
+
});
|
|
365
|
+
return requestId;
|
|
294
366
|
}
|
|
295
367
|
subscribe(channels, markets) {
|
|
296
368
|
this.ensureAuthenticated();
|
|
@@ -415,6 +487,14 @@ export class ActaWsClient extends TypedEventEmitter {
|
|
|
415
487
|
case "AuthError":
|
|
416
488
|
this.handleAuthError(message.data.reason, message.data.message);
|
|
417
489
|
break;
|
|
490
|
+
case "LogoutSuccess":
|
|
491
|
+
this.sessionId = null;
|
|
492
|
+
this.pendingResumeSessionId = null;
|
|
493
|
+
this.lastAuthSessionId = null;
|
|
494
|
+
this.startAuthSent = false;
|
|
495
|
+
this.setConnectionState("connecting");
|
|
496
|
+
this.emit("logoutSuccess");
|
|
497
|
+
break;
|
|
418
498
|
case "Snapshot":
|
|
419
499
|
this.handleSnapshot(message.data);
|
|
420
500
|
break;
|
|
@@ -425,7 +505,13 @@ export class ActaWsClient extends TypedEventEmitter {
|
|
|
425
505
|
this.handleMarkets(message.data.markets ?? []);
|
|
426
506
|
break;
|
|
427
507
|
case "MarketDescriptors":
|
|
428
|
-
|
|
508
|
+
{
|
|
509
|
+
const marketDescriptors = message.data.markets ?? [];
|
|
510
|
+
for (const marketDescriptor of marketDescriptors) {
|
|
511
|
+
this.marketDescriptorsByMarket.set(marketDescriptor.market.market_pda, marketDescriptor);
|
|
512
|
+
}
|
|
513
|
+
this.emit("marketDescriptors", marketDescriptors);
|
|
514
|
+
}
|
|
429
515
|
break;
|
|
430
516
|
case "Expiries":
|
|
431
517
|
this.emit("expiries", message.data.expiries_ts ?? []);
|
|
@@ -584,10 +670,12 @@ export class ActaWsClient extends TypedEventEmitter {
|
|
|
584
670
|
}
|
|
585
671
|
/** Taker-only: request current indicative prices for a market + position_type. */
|
|
586
672
|
getIndicativePrices(req) {
|
|
673
|
+
const requestId = this.nextRequestId();
|
|
587
674
|
this.send({
|
|
588
675
|
type: "GetIndicativePrices",
|
|
589
|
-
data: req,
|
|
676
|
+
data: { ...req, request_id: requestId },
|
|
590
677
|
});
|
|
678
|
+
return requestId;
|
|
591
679
|
}
|
|
592
680
|
/** Maker-only: respond to an indicative request (unsigned, non-binding). */
|
|
593
681
|
sendIndicativePricesResponse(resp) {
|
|
@@ -616,8 +704,9 @@ export class ActaWsClient extends TypedEventEmitter {
|
|
|
616
704
|
}
|
|
617
705
|
}
|
|
618
706
|
async beginAuthHandshake() {
|
|
619
|
-
|
|
620
|
-
|
|
707
|
+
const resumeSessionId = this.pendingResumeSessionId ?? this.lastAuthSessionId;
|
|
708
|
+
if (resumeSessionId) {
|
|
709
|
+
this.sendResumeAuth(resumeSessionId);
|
|
621
710
|
return;
|
|
622
711
|
}
|
|
623
712
|
await this.sendStartAuth();
|
|
@@ -654,6 +743,9 @@ export class ActaWsClient extends TypedEventEmitter {
|
|
|
654
743
|
handleAuthSuccess(sessionId, expiresAt) {
|
|
655
744
|
this.sessionId = sessionId;
|
|
656
745
|
this.pendingResumeSessionId = null;
|
|
746
|
+
if (expiresAt !== null) {
|
|
747
|
+
this.lastAuthSessionId = sessionId;
|
|
748
|
+
}
|
|
657
749
|
this.setConnectionState("authenticated");
|
|
658
750
|
this.emit("authenticated", sessionId, expiresAt);
|
|
659
751
|
if (this.subscribedChannels.size > 0) {
|
|
@@ -665,12 +757,13 @@ export class ActaWsClient extends TypedEventEmitter {
|
|
|
665
757
|
}
|
|
666
758
|
}
|
|
667
759
|
handleAuthError(reason, message) {
|
|
668
|
-
this.emit("authError", reason);
|
|
760
|
+
this.emit("authError", reason, message);
|
|
669
761
|
if (reason === "session_expired" &&
|
|
670
762
|
this.authRequested &&
|
|
671
763
|
this.authProvider &&
|
|
672
|
-
this.pendingResumeSessionId) {
|
|
764
|
+
(this.pendingResumeSessionId || this.lastAuthSessionId)) {
|
|
673
765
|
this.pendingResumeSessionId = null;
|
|
766
|
+
this.lastAuthSessionId = null;
|
|
674
767
|
this.startAuthSent = false;
|
|
675
768
|
void this.sendStartAuth().catch((err) => {
|
|
676
769
|
this.emit("error", err);
|
|
@@ -786,6 +879,9 @@ export class ActaWsClient extends TypedEventEmitter {
|
|
|
786
879
|
this.log("Cannot send, WebSocket not open");
|
|
787
880
|
}
|
|
788
881
|
}
|
|
882
|
+
nextRequestId() {
|
|
883
|
+
return generateRequestId();
|
|
884
|
+
}
|
|
789
885
|
ensureAuthenticated() {
|
|
790
886
|
if (this.connectionState !== "authenticated") {
|
|
791
887
|
throw new Error("Client is not authenticated");
|
|
@@ -880,7 +976,6 @@ export class ActaWsClient extends TypedEventEmitter {
|
|
|
880
976
|
this.helloSent = false;
|
|
881
977
|
this.welcomeReceived = false;
|
|
882
978
|
this.startAuthSent = false;
|
|
883
|
-
this.pendingResumeSessionId = null;
|
|
884
979
|
this.pendingMessages = [];
|
|
885
980
|
this.setConnectionState("disconnected");
|
|
886
981
|
}
|