@acta-markets/ts-sdk 0.0.1-beta → 0.0.3-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.
@@ -38,7 +38,9 @@ export declare class ActaClient {
38
38
  /** Convenience: `client.connectWs(auth)` instead of `client.ws!.connect(auth)`. */
39
39
  connectWs(authProvider: AuthProvider): this;
40
40
  /** Convenience: connect and trigger auth flow in one call. */
41
- connectWsAndAuthenticate(authProvider: AuthProvider): this;
41
+ connectWsAndAuthenticate(authProvider: AuthProvider, options?: {
42
+ sessionId?: string;
43
+ }): this;
42
44
  /** Convenience: connect WS without triggering auth (anonymous browsing). */
43
45
  connectWsAnonymous(): this;
44
46
  /** Convenience: disconnect WS (and stop reconnect timers). */
@@ -82,8 +82,8 @@ export class ActaClient {
82
82
  return this;
83
83
  }
84
84
  /** Convenience: connect and trigger auth flow in one call. */
85
- connectWsAndAuthenticate(authProvider) {
86
- this.assertWs().connectAndAuthenticate(authProvider);
85
+ connectWsAndAuthenticate(authProvider, options) {
86
+ this.assertWs().connectAndAuthenticate(authProvider, options);
87
87
  return this;
88
88
  }
89
89
  /** Convenience: connect WS without triggering auth (anonymous browsing). */
@@ -86,6 +86,13 @@ async function fetchAndDecode(rpc, config, decode) {
86
86
  function dataSize(bytes) {
87
87
  return { dataSize: BigInt(bytes) };
88
88
  }
89
+ function marketAccountFilters(...extra) {
90
+ return [
91
+ dataSize(MARKET_ACCOUNT_SIZE_BYTES),
92
+ memcmp(0, new Uint8Array([MARKET_ACCOUNT_DISCRIMINATOR])),
93
+ ...extra,
94
+ ];
95
+ }
89
96
  // --- Positions ---
90
97
  export async function fetchPositionsByMaker(rpc, makerOwner, options) {
91
98
  return rpc
@@ -236,10 +243,7 @@ export async function fetchAllMarketsDecoded(rpc, options) {
236
243
  return fetchAndDecode(rpc, {
237
244
  commitment: options?.commitment,
238
245
  dataSlice: options?.dataSlice,
239
- filters: [
240
- dataSize(MARKET_ACCOUNT_SIZE_BYTES),
241
- memcmp(0, new Uint8Array([MARKET_ACCOUNT_DISCRIMINATOR])),
242
- ],
246
+ filters: marketAccountFilters(),
243
247
  }, decodeMarketAccount);
244
248
  }
245
249
  export async function fetchAllOraclesDecoded(rpc, options) {
@@ -268,7 +272,7 @@ export async function fetchMarketsByUnderlying(rpc, underlying, options) {
268
272
  .getProgramAccounts(getActaProgramId(), {
269
273
  commitment: options?.commitment,
270
274
  dataSlice: options?.dataSlice,
271
- filters: [memcmp(MARKET_OFFSET_UNDERLYING_MINT, addrBytes(underlying))],
275
+ filters: marketAccountFilters(memcmp(MARKET_OFFSET_UNDERLYING_MINT, addrBytes(underlying))),
272
276
  })
273
277
  .send();
274
278
  }
@@ -276,7 +280,7 @@ export async function fetchMarketsByUnderlyingDecoded(rpc, underlying, options)
276
280
  return fetchAndDecode(rpc, {
277
281
  commitment: options?.commitment,
278
282
  dataSlice: options?.dataSlice,
279
- filters: [memcmp(MARKET_OFFSET_UNDERLYING_MINT, addrBytes(underlying))],
283
+ filters: marketAccountFilters(memcmp(MARKET_OFFSET_UNDERLYING_MINT, addrBytes(underlying))),
280
284
  }, decodeMarketAccount);
281
285
  }
282
286
  export async function fetchMarketsByQuote(rpc, quote, options) {
@@ -284,7 +288,7 @@ export async function fetchMarketsByQuote(rpc, quote, options) {
284
288
  .getProgramAccounts(getActaProgramId(), {
285
289
  commitment: options?.commitment,
286
290
  dataSlice: options?.dataSlice,
287
- filters: [memcmp(MARKET_OFFSET_QUOTE_MINT, addrBytes(quote))],
291
+ filters: marketAccountFilters(memcmp(MARKET_OFFSET_QUOTE_MINT, addrBytes(quote))),
288
292
  })
289
293
  .send();
290
294
  }
@@ -292,7 +296,7 @@ export async function fetchMarketsByQuoteDecoded(rpc, quote, options) {
292
296
  return fetchAndDecode(rpc, {
293
297
  commitment: options?.commitment,
294
298
  dataSlice: options?.dataSlice,
295
- filters: [memcmp(MARKET_OFFSET_QUOTE_MINT, addrBytes(quote))],
299
+ filters: marketAccountFilters(memcmp(MARKET_OFFSET_QUOTE_MINT, addrBytes(quote))),
296
300
  }, decodeMarketAccount);
297
301
  }
298
302
  export async function fetchMarketsByExpiry(rpc, expiryTs, options) {
@@ -300,7 +304,7 @@ export async function fetchMarketsByExpiry(rpc, expiryTs, options) {
300
304
  .getProgramAccounts(getActaProgramId(), {
301
305
  commitment: options?.commitment,
302
306
  dataSlice: options?.dataSlice,
303
- filters: [memcmp(MARKET_OFFSET_EXPIRY_TS, u64Le(expiryTs))],
307
+ filters: marketAccountFilters(memcmp(MARKET_OFFSET_EXPIRY_TS, u64Le(expiryTs))),
304
308
  })
305
309
  .send();
306
310
  }
@@ -308,7 +312,7 @@ export async function fetchMarketsByExpiryDecoded(rpc, expiryTs, options) {
308
312
  return fetchAndDecode(rpc, {
309
313
  commitment: options?.commitment,
310
314
  dataSlice: options?.dataSlice,
311
- filters: [memcmp(MARKET_OFFSET_EXPIRY_TS, u64Le(expiryTs))],
315
+ filters: marketAccountFilters(memcmp(MARKET_OFFSET_EXPIRY_TS, u64Le(expiryTs))),
312
316
  }, decodeMarketAccount);
313
317
  }
314
318
  export async function fetchMarketsByQuoteAndExpiry(rpc, quote, expiryTs, options) {
@@ -316,10 +320,7 @@ export async function fetchMarketsByQuoteAndExpiry(rpc, quote, expiryTs, options
316
320
  .getProgramAccounts(getActaProgramId(), {
317
321
  commitment: options?.commitment,
318
322
  dataSlice: options?.dataSlice,
319
- filters: [
320
- memcmp(MARKET_OFFSET_QUOTE_MINT, addrBytes(quote)),
321
- memcmp(MARKET_OFFSET_EXPIRY_TS, u64Le(expiryTs)),
322
- ],
323
+ filters: marketAccountFilters(memcmp(MARKET_OFFSET_QUOTE_MINT, addrBytes(quote)), memcmp(MARKET_OFFSET_EXPIRY_TS, u64Le(expiryTs))),
323
324
  })
324
325
  .send();
325
326
  }
@@ -327,10 +328,7 @@ export async function fetchMarketsByQuoteAndExpiryDecoded(rpc, quote, expiryTs,
327
328
  return fetchAndDecode(rpc, {
328
329
  commitment: options?.commitment,
329
330
  dataSlice: options?.dataSlice,
330
- filters: [
331
- memcmp(MARKET_OFFSET_QUOTE_MINT, addrBytes(quote)),
332
- memcmp(MARKET_OFFSET_EXPIRY_TS, u64Le(expiryTs)),
333
- ],
331
+ filters: marketAccountFilters(memcmp(MARKET_OFFSET_QUOTE_MINT, addrBytes(quote)), memcmp(MARKET_OFFSET_EXPIRY_TS, u64Le(expiryTs))),
334
332
  }, decodeMarketAccount);
335
333
  }
336
334
  export async function fetchMarketsByUnderlyingAndExpiry(rpc, underlying, expiryTs, options) {
@@ -338,10 +336,7 @@ export async function fetchMarketsByUnderlyingAndExpiry(rpc, underlying, expiryT
338
336
  .getProgramAccounts(getActaProgramId(), {
339
337
  commitment: options?.commitment,
340
338
  dataSlice: options?.dataSlice,
341
- filters: [
342
- memcmp(MARKET_OFFSET_UNDERLYING_MINT, addrBytes(underlying)),
343
- memcmp(MARKET_OFFSET_EXPIRY_TS, u64Le(expiryTs)),
344
- ],
339
+ filters: marketAccountFilters(memcmp(MARKET_OFFSET_UNDERLYING_MINT, addrBytes(underlying)), memcmp(MARKET_OFFSET_EXPIRY_TS, u64Le(expiryTs))),
345
340
  })
346
341
  .send();
347
342
  }
@@ -368,10 +363,7 @@ export async function fetchMarketsByUnderlyingAndExpiryDecoded(rpc, underlying,
368
363
  return fetchAndDecode(rpc, {
369
364
  commitment: options?.commitment,
370
365
  dataSlice: options?.dataSlice,
371
- filters: [
372
- memcmp(MARKET_OFFSET_UNDERLYING_MINT, addrBytes(underlying)),
373
- memcmp(MARKET_OFFSET_EXPIRY_TS, u64Le(expiryTs)),
374
- ],
366
+ filters: marketAccountFilters(memcmp(MARKET_OFFSET_UNDERLYING_MINT, addrBytes(underlying)), memcmp(MARKET_OFFSET_EXPIRY_TS, u64Le(expiryTs))),
375
367
  }, decodeMarketAccount);
376
368
  }
377
369
  // --- Decode helpers ---
@@ -379,6 +371,12 @@ export function decodePositionAccount(data) {
379
371
  return getPositionDecoder().decode(data);
380
372
  }
381
373
  export function decodeMarketAccount(data) {
374
+ if (data.length < MARKET_ACCOUNT_SIZE_BYTES) {
375
+ throw new Error(`Invalid Market account size: expected >= ${MARKET_ACCOUNT_SIZE_BYTES}, got ${data.length}`);
376
+ }
377
+ if (data[0] !== MARKET_ACCOUNT_DISCRIMINATOR) {
378
+ throw new Error(`Invalid Market account discriminator: expected ${MARKET_ACCOUNT_DISCRIMINATOR}, got ${data[0]}`);
379
+ }
382
380
  return getMarketDecoder().decode(data);
383
381
  }
384
382
  export function decodeConfigAccount(data) {
@@ -1,4 +1,4 @@
1
- import { MAKER_OFFSET_MAKER_OWNER, MAKER_OFFSET_QUOTE_SIGNING, MARKET_OFFSET_EXPIRY_TS, MARKET_OFFSET_FLAGS, MARKET_OFFSET_SETTLEMENT_PRICE, MARKET_OFFSET_UNDERLYING_DECIMALS, MARKET_OFFSET_QUOTE_DECIMALS, MARKET_OFFSET_QUOTE_MINT, MARKET_OFFSET_QUOTE_ORACLE_ADDRESS, MARKET_OFFSET_UNDERLYING_MINT, MARKET_OFFSET_UNDERLYING_ORACLE_ADDRESS, POSITION_OFFSET_MAKER_OWNER, POSITION_OFFSET_MARKET, POSITION_OFFSET_STATUS, POSITION_OFFSET_TAKER_OWNER, } from "./fetch";
1
+ import { decodeMarketAccount, MAKER_OFFSET_MAKER_OWNER, MAKER_OFFSET_QUOTE_SIGNING, MARKET_OFFSET_EXPIRY_TS, MARKET_OFFSET_FLAGS, MARKET_OFFSET_SETTLEMENT_PRICE, MARKET_OFFSET_UNDERLYING_DECIMALS, MARKET_OFFSET_QUOTE_DECIMALS, MARKET_OFFSET_QUOTE_MINT, MARKET_OFFSET_QUOTE_ORACLE_ADDRESS, MARKET_OFFSET_UNDERLYING_MINT, MARKET_OFFSET_UNDERLYING_ORACLE_ADDRESS, POSITION_OFFSET_MAKER_OWNER, POSITION_OFFSET_MARKET, POSITION_OFFSET_STATUS, POSITION_OFFSET_TAKER_OWNER, } from "./fetch";
2
2
  import { getAddressDecoder } from "@solana/addresses";
3
3
  import { encodeOrderPreimage } from "./orders";
4
4
  import { getMakerEncoder, getMakerSize } from "../generated/accounts/maker";
@@ -155,4 +155,33 @@ describe("fetch offsets and order encode", () => {
155
155
  expect(preimage.slice(base + 66, base + 98)).toEqual(makerBytes);
156
156
  expect(preimage.slice(base + 98, base + 130)).toEqual(takerBytes);
157
157
  });
158
+ it("decodeMarketAccount rejects non-market discriminator and short data", () => {
159
+ const decoder = getAddressDecoder();
160
+ const marketBytes = new Uint8Array(Array(32).fill(1));
161
+ const makerBytes = new Uint8Array(Array(32).fill(7));
162
+ const takerBytes = new Uint8Array(Array(32).fill(8));
163
+ const market = decoder.decode(marketBytes);
164
+ const makerOwner = decoder.decode(makerBytes);
165
+ const takerOwner = decoder.decode(takerBytes);
166
+ const positionData = getPositionEncoder().encode({
167
+ discriminator: 1,
168
+ version: 1,
169
+ bump: 7,
170
+ positionType: 0,
171
+ status: 1,
172
+ flags: 0,
173
+ flags2: 0,
174
+ flags3: 0,
175
+ takerOwner,
176
+ makerOwner,
177
+ market,
178
+ strike: 1n,
179
+ quantity: 1n,
180
+ totalPremium: 1n,
181
+ orderId: new Uint8Array(32).fill(0x11),
182
+ reserved: Array(32).fill(0n),
183
+ });
184
+ expect(() => decodeMarketAccount(Buffer.from(positionData))).toThrow("Invalid Market account discriminator");
185
+ expect(() => decodeMarketAccount(Buffer.alloc(8))).toThrow("Invalid Market account size");
186
+ });
158
187
  });
@@ -85,8 +85,8 @@ class ActaClient {
85
85
  return this;
86
86
  }
87
87
  /** Convenience: connect and trigger auth flow in one call. */
88
- connectWsAndAuthenticate(authProvider) {
89
- this.assertWs().connectAndAuthenticate(authProvider);
88
+ connectWsAndAuthenticate(authProvider, options) {
89
+ this.assertWs().connectAndAuthenticate(authProvider, options);
90
90
  return this;
91
91
  }
92
92
  /** Convenience: connect WS without triggering auth (anonymous browsing). */
@@ -125,6 +125,13 @@ async function fetchAndDecode(rpc, config, decode) {
125
125
  function dataSize(bytes) {
126
126
  return { dataSize: BigInt(bytes) };
127
127
  }
128
+ function marketAccountFilters(...extra) {
129
+ return [
130
+ dataSize(exports.MARKET_ACCOUNT_SIZE_BYTES),
131
+ memcmp(0, new Uint8Array([exports.MARKET_ACCOUNT_DISCRIMINATOR])),
132
+ ...extra,
133
+ ];
134
+ }
128
135
  // --- Positions ---
129
136
  async function fetchPositionsByMaker(rpc, makerOwner, options) {
130
137
  return rpc
@@ -275,10 +282,7 @@ async function fetchAllMarketsDecoded(rpc, options) {
275
282
  return fetchAndDecode(rpc, {
276
283
  commitment: options?.commitment,
277
284
  dataSlice: options?.dataSlice,
278
- filters: [
279
- dataSize(exports.MARKET_ACCOUNT_SIZE_BYTES),
280
- memcmp(0, new Uint8Array([exports.MARKET_ACCOUNT_DISCRIMINATOR])),
281
- ],
285
+ filters: marketAccountFilters(),
282
286
  }, decodeMarketAccount);
283
287
  }
284
288
  async function fetchAllOraclesDecoded(rpc, options) {
@@ -307,7 +311,7 @@ async function fetchMarketsByUnderlying(rpc, underlying, options) {
307
311
  .getProgramAccounts((0, index_1.getActaProgramId)(), {
308
312
  commitment: options?.commitment,
309
313
  dataSlice: options?.dataSlice,
310
- filters: [memcmp(exports.MARKET_OFFSET_UNDERLYING_MINT, addrBytes(underlying))],
314
+ filters: marketAccountFilters(memcmp(exports.MARKET_OFFSET_UNDERLYING_MINT, addrBytes(underlying))),
311
315
  })
312
316
  .send();
313
317
  }
@@ -315,7 +319,7 @@ async function fetchMarketsByUnderlyingDecoded(rpc, underlying, options) {
315
319
  return fetchAndDecode(rpc, {
316
320
  commitment: options?.commitment,
317
321
  dataSlice: options?.dataSlice,
318
- filters: [memcmp(exports.MARKET_OFFSET_UNDERLYING_MINT, addrBytes(underlying))],
322
+ filters: marketAccountFilters(memcmp(exports.MARKET_OFFSET_UNDERLYING_MINT, addrBytes(underlying))),
319
323
  }, decodeMarketAccount);
320
324
  }
321
325
  async function fetchMarketsByQuote(rpc, quote, options) {
@@ -323,7 +327,7 @@ async function fetchMarketsByQuote(rpc, quote, options) {
323
327
  .getProgramAccounts((0, index_1.getActaProgramId)(), {
324
328
  commitment: options?.commitment,
325
329
  dataSlice: options?.dataSlice,
326
- filters: [memcmp(exports.MARKET_OFFSET_QUOTE_MINT, addrBytes(quote))],
330
+ filters: marketAccountFilters(memcmp(exports.MARKET_OFFSET_QUOTE_MINT, addrBytes(quote))),
327
331
  })
328
332
  .send();
329
333
  }
@@ -331,7 +335,7 @@ async function fetchMarketsByQuoteDecoded(rpc, quote, options) {
331
335
  return fetchAndDecode(rpc, {
332
336
  commitment: options?.commitment,
333
337
  dataSlice: options?.dataSlice,
334
- filters: [memcmp(exports.MARKET_OFFSET_QUOTE_MINT, addrBytes(quote))],
338
+ filters: marketAccountFilters(memcmp(exports.MARKET_OFFSET_QUOTE_MINT, addrBytes(quote))),
335
339
  }, decodeMarketAccount);
336
340
  }
337
341
  async function fetchMarketsByExpiry(rpc, expiryTs, options) {
@@ -339,7 +343,7 @@ async function fetchMarketsByExpiry(rpc, expiryTs, options) {
339
343
  .getProgramAccounts((0, index_1.getActaProgramId)(), {
340
344
  commitment: options?.commitment,
341
345
  dataSlice: options?.dataSlice,
342
- filters: [memcmp(exports.MARKET_OFFSET_EXPIRY_TS, u64Le(expiryTs))],
346
+ filters: marketAccountFilters(memcmp(exports.MARKET_OFFSET_EXPIRY_TS, u64Le(expiryTs))),
343
347
  })
344
348
  .send();
345
349
  }
@@ -347,7 +351,7 @@ async function fetchMarketsByExpiryDecoded(rpc, expiryTs, options) {
347
351
  return fetchAndDecode(rpc, {
348
352
  commitment: options?.commitment,
349
353
  dataSlice: options?.dataSlice,
350
- filters: [memcmp(exports.MARKET_OFFSET_EXPIRY_TS, u64Le(expiryTs))],
354
+ filters: marketAccountFilters(memcmp(exports.MARKET_OFFSET_EXPIRY_TS, u64Le(expiryTs))),
351
355
  }, decodeMarketAccount);
352
356
  }
353
357
  async function fetchMarketsByQuoteAndExpiry(rpc, quote, expiryTs, options) {
@@ -355,10 +359,7 @@ async function fetchMarketsByQuoteAndExpiry(rpc, quote, expiryTs, options) {
355
359
  .getProgramAccounts((0, index_1.getActaProgramId)(), {
356
360
  commitment: options?.commitment,
357
361
  dataSlice: options?.dataSlice,
358
- filters: [
359
- memcmp(exports.MARKET_OFFSET_QUOTE_MINT, addrBytes(quote)),
360
- memcmp(exports.MARKET_OFFSET_EXPIRY_TS, u64Le(expiryTs)),
361
- ],
362
+ filters: marketAccountFilters(memcmp(exports.MARKET_OFFSET_QUOTE_MINT, addrBytes(quote)), memcmp(exports.MARKET_OFFSET_EXPIRY_TS, u64Le(expiryTs))),
362
363
  })
363
364
  .send();
364
365
  }
@@ -366,10 +367,7 @@ async function fetchMarketsByQuoteAndExpiryDecoded(rpc, quote, expiryTs, options
366
367
  return fetchAndDecode(rpc, {
367
368
  commitment: options?.commitment,
368
369
  dataSlice: options?.dataSlice,
369
- filters: [
370
- memcmp(exports.MARKET_OFFSET_QUOTE_MINT, addrBytes(quote)),
371
- memcmp(exports.MARKET_OFFSET_EXPIRY_TS, u64Le(expiryTs)),
372
- ],
370
+ filters: marketAccountFilters(memcmp(exports.MARKET_OFFSET_QUOTE_MINT, addrBytes(quote)), memcmp(exports.MARKET_OFFSET_EXPIRY_TS, u64Le(expiryTs))),
373
371
  }, decodeMarketAccount);
374
372
  }
375
373
  async function fetchMarketsByUnderlyingAndExpiry(rpc, underlying, expiryTs, options) {
@@ -377,10 +375,7 @@ async function fetchMarketsByUnderlyingAndExpiry(rpc, underlying, expiryTs, opti
377
375
  .getProgramAccounts((0, index_1.getActaProgramId)(), {
378
376
  commitment: options?.commitment,
379
377
  dataSlice: options?.dataSlice,
380
- filters: [
381
- memcmp(exports.MARKET_OFFSET_UNDERLYING_MINT, addrBytes(underlying)),
382
- memcmp(exports.MARKET_OFFSET_EXPIRY_TS, u64Le(expiryTs)),
383
- ],
378
+ filters: marketAccountFilters(memcmp(exports.MARKET_OFFSET_UNDERLYING_MINT, addrBytes(underlying)), memcmp(exports.MARKET_OFFSET_EXPIRY_TS, u64Le(expiryTs))),
384
379
  })
385
380
  .send();
386
381
  }
@@ -407,10 +402,7 @@ async function fetchMarketsByUnderlyingAndExpiryDecoded(rpc, underlying, expiryT
407
402
  return fetchAndDecode(rpc, {
408
403
  commitment: options?.commitment,
409
404
  dataSlice: options?.dataSlice,
410
- filters: [
411
- memcmp(exports.MARKET_OFFSET_UNDERLYING_MINT, addrBytes(underlying)),
412
- memcmp(exports.MARKET_OFFSET_EXPIRY_TS, u64Le(expiryTs)),
413
- ],
405
+ filters: marketAccountFilters(memcmp(exports.MARKET_OFFSET_UNDERLYING_MINT, addrBytes(underlying)), memcmp(exports.MARKET_OFFSET_EXPIRY_TS, u64Le(expiryTs))),
414
406
  }, decodeMarketAccount);
415
407
  }
416
408
  // --- Decode helpers ---
@@ -418,6 +410,12 @@ function decodePositionAccount(data) {
418
410
  return (0, position_1.getPositionDecoder)().decode(data);
419
411
  }
420
412
  function decodeMarketAccount(data) {
413
+ if (data.length < exports.MARKET_ACCOUNT_SIZE_BYTES) {
414
+ throw new Error(`Invalid Market account size: expected >= ${exports.MARKET_ACCOUNT_SIZE_BYTES}, got ${data.length}`);
415
+ }
416
+ if (data[0] !== exports.MARKET_ACCOUNT_DISCRIMINATOR) {
417
+ throw new Error(`Invalid Market account discriminator: expected ${exports.MARKET_ACCOUNT_DISCRIMINATOR}, got ${data[0]}`);
418
+ }
421
419
  return (0, market_1.getMarketDecoder)().decode(data);
422
420
  }
423
421
  function decodeConfigAccount(data) {
@@ -157,4 +157,33 @@ describe("fetch offsets and order encode", () => {
157
157
  expect(preimage.slice(base + 66, base + 98)).toEqual(makerBytes);
158
158
  expect(preimage.slice(base + 98, base + 130)).toEqual(takerBytes);
159
159
  });
160
+ it("decodeMarketAccount rejects non-market discriminator and short data", () => {
161
+ const decoder = (0, addresses_1.getAddressDecoder)();
162
+ const marketBytes = new Uint8Array(Array(32).fill(1));
163
+ const makerBytes = new Uint8Array(Array(32).fill(7));
164
+ const takerBytes = new Uint8Array(Array(32).fill(8));
165
+ const market = decoder.decode(marketBytes);
166
+ const makerOwner = decoder.decode(makerBytes);
167
+ const takerOwner = decoder.decode(takerBytes);
168
+ const positionData = (0, position_1.getPositionEncoder)().encode({
169
+ discriminator: 1,
170
+ version: 1,
171
+ bump: 7,
172
+ positionType: 0,
173
+ status: 1,
174
+ flags: 0,
175
+ flags2: 0,
176
+ flags3: 0,
177
+ takerOwner,
178
+ makerOwner,
179
+ market,
180
+ strike: 1n,
181
+ quantity: 1n,
182
+ totalPremium: 1n,
183
+ orderId: new Uint8Array(32).fill(0x11),
184
+ reserved: Array(32).fill(0n),
185
+ });
186
+ expect(() => (0, fetch_1.decodeMarketAccount)(buffer_1.Buffer.from(positionData))).toThrow("Invalid Market account discriminator");
187
+ expect(() => (0, fetch_1.decodeMarketAccount)(buffer_1.Buffer.alloc(8))).toThrow("Invalid Market account size");
188
+ });
160
189
  });
@@ -79,6 +79,7 @@ class ActaWsClient extends TypedEventEmitter {
79
79
  authProvider = null;
80
80
  authRequested = false;
81
81
  startAuthSent = false;
82
+ pendingResumeSessionId = null;
82
83
  connectionState = "disconnected";
83
84
  sessionId = null;
84
85
  helloSent = false;
@@ -122,22 +123,25 @@ class ActaWsClient extends TypedEventEmitter {
122
123
  connectAnonymous() {
123
124
  this.authProvider = null;
124
125
  this.authRequested = false;
126
+ this.pendingResumeSessionId = null;
125
127
  this.shouldReconnect = this.options.autoReconnect;
126
128
  this.doConnect();
127
129
  }
128
130
  connect(authProvider) {
129
131
  this.authProvider = authProvider;
130
132
  this.authRequested = false;
133
+ this.pendingResumeSessionId = null;
131
134
  this.shouldReconnect = this.options.autoReconnect;
132
135
  this.doConnect();
133
136
  }
134
- connectAndAuthenticate(authProvider) {
137
+ connectAndAuthenticate(authProvider, options) {
135
138
  this.authProvider = authProvider;
136
139
  this.authRequested = true;
140
+ this.pendingResumeSessionId = options?.sessionId ?? null;
137
141
  this.shouldReconnect = this.options.autoReconnect;
138
142
  if (this.ws?.readyState === WS_OPEN) {
139
143
  if (this.welcomeReceived && !this.startAuthSent) {
140
- void this.sendStartAuth().catch((err) => {
144
+ void this.beginAuthHandshake().catch((err) => {
141
145
  this.emit("error", err);
142
146
  this.setConnectionState("error");
143
147
  });
@@ -149,6 +153,7 @@ class ActaWsClient extends TypedEventEmitter {
149
153
  async authenticate(authProvider) {
150
154
  this.authProvider = authProvider;
151
155
  this.authRequested = true;
156
+ this.pendingResumeSessionId = null;
152
157
  if (this.ws?.readyState === WS_OPEN) {
153
158
  if (this.welcomeReceived && !this.startAuthSent) {
154
159
  await this.sendStartAuth();
@@ -319,6 +324,10 @@ class ActaWsClient extends TypedEventEmitter {
319
324
  this.send({ type: "Ping" });
320
325
  }
321
326
  }
327
+ resumeAuth(sessionId) {
328
+ this.pendingResumeSessionId = sessionId;
329
+ this.sendResumeAuth(sessionId);
330
+ }
322
331
  doConnect() {
323
332
  if (this.ws) {
324
333
  this.cleanup();
@@ -379,7 +388,7 @@ class ActaWsClient extends TypedEventEmitter {
379
388
  this.emit("welcome", message.data);
380
389
  this.flushPendingMessages();
381
390
  if (this.authRequested && this.authProvider && !this.startAuthSent) {
382
- void this.sendStartAuth().catch((err) => {
391
+ void this.beginAuthHandshake().catch((err) => {
383
392
  this.emit("error", err);
384
393
  this.setConnectionState("error");
385
394
  });
@@ -404,10 +413,10 @@ class ActaWsClient extends TypedEventEmitter {
404
413
  void this.handleAuthRequest(message.data.challenge);
405
414
  break;
406
415
  case "AuthSuccess":
407
- this.handleAuthSuccess(message.data.session_id);
416
+ this.handleAuthSuccess(message.data.session_id, message.data.expires_at);
408
417
  break;
409
418
  case "AuthError":
410
- this.handleAuthError(message.data.reason);
419
+ this.handleAuthError(message.data.reason, message.data.message);
411
420
  break;
412
421
  case "Snapshot":
413
422
  this.handleSnapshot(message.data);
@@ -609,6 +618,13 @@ class ActaWsClient extends TypedEventEmitter {
609
618
  this.setConnectionState("error");
610
619
  }
611
620
  }
621
+ async beginAuthHandshake() {
622
+ if (this.pendingResumeSessionId) {
623
+ this.sendResumeAuth(this.pendingResumeSessionId);
624
+ return;
625
+ }
626
+ await this.sendStartAuth();
627
+ }
612
628
  async sendStartAuth() {
613
629
  if (!this.authProvider)
614
630
  throw new Error("No auth provider configured");
@@ -616,6 +632,10 @@ class ActaWsClient extends TypedEventEmitter {
616
632
  const pubkey = await this.authProvider.getPublicKey();
617
633
  this.send({ type: "StartAuth", data: { pubkey } });
618
634
  }
635
+ sendResumeAuth(sessionId) {
636
+ this.startAuthSent = true;
637
+ this.send({ type: "ResumeAuth", data: { session_id: sessionId } });
638
+ }
619
639
  sendHello() {
620
640
  const hello = {
621
641
  protocol_version: this.options.protocolVersion,
@@ -634,10 +654,11 @@ class ActaWsClient extends TypedEventEmitter {
634
654
  this.send(msg);
635
655
  }
636
656
  }
637
- handleAuthSuccess(sessionId) {
657
+ handleAuthSuccess(sessionId, expiresAt) {
638
658
  this.sessionId = sessionId;
659
+ this.pendingResumeSessionId = null;
639
660
  this.setConnectionState("authenticated");
640
- this.emit("authenticated", sessionId);
661
+ this.emit("authenticated", sessionId, expiresAt);
641
662
  if (this.subscribedChannels.size > 0) {
642
663
  const channels = Array.from(this.subscribedChannels);
643
664
  const data = this.hasMarketScope
@@ -646,9 +667,23 @@ class ActaWsClient extends TypedEventEmitter {
646
667
  this.send({ type: "Subscribe", data });
647
668
  }
648
669
  }
649
- handleAuthError(reason) {
670
+ handleAuthError(reason, message) {
671
+ this.emit("authError", reason);
672
+ if (reason === "session_expired" &&
673
+ this.authRequested &&
674
+ this.authProvider &&
675
+ this.pendingResumeSessionId) {
676
+ this.pendingResumeSessionId = null;
677
+ this.startAuthSent = false;
678
+ void this.sendStartAuth().catch((err) => {
679
+ this.emit("error", err);
680
+ this.setConnectionState("error");
681
+ });
682
+ return;
683
+ }
650
684
  this.setConnectionState("error");
651
- this.emit("error", new Error(`Authentication failed: ${reason}`));
685
+ const details = message ? `${reason}: ${message}` : reason;
686
+ this.emit("error", new Error(`Authentication failed: ${details}`));
652
687
  }
653
688
  handleSnapshot(snapshot) {
654
689
  this.state.stats = snapshot.stats;
@@ -848,6 +883,7 @@ class ActaWsClient extends TypedEventEmitter {
848
883
  this.helloSent = false;
849
884
  this.welcomeReceived = false;
850
885
  this.startAuthSent = false;
886
+ this.pendingResumeSessionId = null;
851
887
  this.pendingMessages = [];
852
888
  this.setConnectionState("disconnected");
853
889
  }
@@ -121,6 +121,62 @@ describe("ActaWsClient", () => {
121
121
  expect(authChallenge.data.challenge).toBe("challenge-text");
122
122
  }
123
123
  });
124
+ it("connectAndAuthenticate sends ResumeAuth when sessionId is provided", async () => {
125
+ const { client, socket } = makeHarness();
126
+ const auth = makeAuthProvider("WalletPubkey", "WalletSignature");
127
+ client.connectAndAuthenticate(auth, { sessionId: "resume-session-id" });
128
+ const ws = socket();
129
+ ws.triggerOpen();
130
+ ws.triggerMessage(WELCOME_MESSAGE);
131
+ await flushMicrotasks();
132
+ const sentTypes = ws.sent.map((payload) => parseClientMessage(payload).type);
133
+ expect(sentTypes).toEqual(["Hello", "ResumeAuth"]);
134
+ const resumeAuth = parseClientMessage(ws.sent[1]);
135
+ expect(resumeAuth.type).toBe("ResumeAuth");
136
+ if (resumeAuth.type === "ResumeAuth") {
137
+ expect(resumeAuth.data.session_id).toBe("resume-session-id");
138
+ }
139
+ });
140
+ it("falls back to StartAuth when ResumeAuth session_expired", async () => {
141
+ const { client, socket } = makeHarness();
142
+ const auth = makeAuthProvider("WalletPubkey", "WalletSignature");
143
+ client.connectAndAuthenticate(auth, { sessionId: "expired-session" });
144
+ const ws = socket();
145
+ ws.triggerOpen();
146
+ ws.triggerMessage(WELCOME_MESSAGE);
147
+ await flushMicrotasks();
148
+ ws.triggerMessage({
149
+ type: "AuthError",
150
+ data: { reason: "session_expired" },
151
+ });
152
+ await flushMicrotasks();
153
+ const sentTypes = ws.sent.map((payload) => parseClientMessage(payload).type);
154
+ expect(sentTypes).toEqual(["Hello", "ResumeAuth", "StartAuth"]);
155
+ });
156
+ it("emits authenticated with expiresAt from AuthSuccess", () => {
157
+ const { client } = makeHarness();
158
+ const seen = [];
159
+ client.on("authenticated", (sessionId, expiresAt) => {
160
+ seen.push({ sessionId, expiresAt });
161
+ });
162
+ client.handleMessage({
163
+ type: "AuthSuccess",
164
+ data: { session_id: "auth-session", expires_at: 1_710_086_400 },
165
+ });
166
+ expect(seen).toEqual([
167
+ { sessionId: "auth-session", expiresAt: 1_710_086_400 },
168
+ ]);
169
+ });
170
+ it("emits authError reason on AuthError", () => {
171
+ const { client } = makeHarness();
172
+ const reasons = [];
173
+ client.on("authError", (reason) => reasons.push(reason));
174
+ client.handleMessage({
175
+ type: "AuthError",
176
+ data: { reason: "invalid_signature", message: "bad signature bytes" },
177
+ });
178
+ expect(reasons).toEqual(["invalid_signature"]);
179
+ });
124
180
  it("drop_oldest policy keeps the latest queued messages", () => {
125
181
  const { client, socket } = makeHarness({
126
182
  maxPendingMessages: 2,
@@ -56,7 +56,8 @@ export type ActaWsClientEvents = {
56
56
  connected: () => void;
57
57
  welcome: (msg: WelcomeMessage) => void;
58
58
  versionMismatch: (msg: VersionMismatchMessage) => void;
59
- authenticated: (sessionId: string) => void;
59
+ authenticated: (sessionId: string, expiresAt: number | null) => void;
60
+ authError: (reason: string) => void;
60
61
  disconnected: (code: number, reason: string) => void;
61
62
  error: (error: Error) => void;
62
63
  stateChange: (state: ConnectionState) => void;
@@ -147,6 +148,7 @@ export declare class ActaWsClient extends TypedEventEmitter<ActaWsClientEvents>
147
148
  private authProvider;
148
149
  private authRequested;
149
150
  private startAuthSent;
151
+ private pendingResumeSessionId;
150
152
  private connectionState;
151
153
  private sessionId;
152
154
  private helloSent;
@@ -163,7 +165,9 @@ export declare class ActaWsClient extends TypedEventEmitter<ActaWsClientEvents>
163
165
  constructor(options: ActaWsClientOptions);
164
166
  connectAnonymous(): void;
165
167
  connect(authProvider: AuthProvider): void;
166
- connectAndAuthenticate(authProvider: AuthProvider): void;
168
+ connectAndAuthenticate(authProvider: AuthProvider, options?: {
169
+ sessionId?: string;
170
+ }): void;
167
171
  authenticate(authProvider: AuthProvider): Promise<void>;
168
172
  disconnect(): void;
169
173
  getConnectionState(): ConnectionState;
@@ -228,6 +232,7 @@ export declare class ActaWsClient extends TypedEventEmitter<ActaWsClientEvents>
228
232
  subscribe(channels: WsChannel[], markets?: string[]): void;
229
233
  unsubscribe(channels: WsChannel[]): void;
230
234
  ping(): void;
235
+ resumeAuth(sessionId: string): void;
231
236
  private doConnect;
232
237
  private handleMessage;
233
238
  /** Taker-only: request current indicative prices for a market + position_type. */
@@ -235,7 +240,9 @@ export declare class ActaWsClient extends TypedEventEmitter<ActaWsClientEvents>
235
240
  /** Maker-only: respond to an indicative request (unsigned, non-binding). */
236
241
  sendIndicativePricesResponse(resp: IndicativePricesResponseMessage): void;
237
242
  private handleAuthRequest;
243
+ private beginAuthHandshake;
238
244
  private sendStartAuth;
245
+ private sendResumeAuth;
239
246
  private sendHello;
240
247
  private flushPendingMessages;
241
248
  private handleAuthSuccess;
package/dist/ws/client.js CHANGED
@@ -76,6 +76,7 @@ export class ActaWsClient extends TypedEventEmitter {
76
76
  authProvider = null;
77
77
  authRequested = false;
78
78
  startAuthSent = false;
79
+ pendingResumeSessionId = null;
79
80
  connectionState = "disconnected";
80
81
  sessionId = null;
81
82
  helloSent = false;
@@ -119,22 +120,25 @@ export class ActaWsClient extends TypedEventEmitter {
119
120
  connectAnonymous() {
120
121
  this.authProvider = null;
121
122
  this.authRequested = false;
123
+ this.pendingResumeSessionId = null;
122
124
  this.shouldReconnect = this.options.autoReconnect;
123
125
  this.doConnect();
124
126
  }
125
127
  connect(authProvider) {
126
128
  this.authProvider = authProvider;
127
129
  this.authRequested = false;
130
+ this.pendingResumeSessionId = null;
128
131
  this.shouldReconnect = this.options.autoReconnect;
129
132
  this.doConnect();
130
133
  }
131
- connectAndAuthenticate(authProvider) {
134
+ connectAndAuthenticate(authProvider, options) {
132
135
  this.authProvider = authProvider;
133
136
  this.authRequested = true;
137
+ this.pendingResumeSessionId = options?.sessionId ?? null;
134
138
  this.shouldReconnect = this.options.autoReconnect;
135
139
  if (this.ws?.readyState === WS_OPEN) {
136
140
  if (this.welcomeReceived && !this.startAuthSent) {
137
- void this.sendStartAuth().catch((err) => {
141
+ void this.beginAuthHandshake().catch((err) => {
138
142
  this.emit("error", err);
139
143
  this.setConnectionState("error");
140
144
  });
@@ -146,6 +150,7 @@ export class ActaWsClient extends TypedEventEmitter {
146
150
  async authenticate(authProvider) {
147
151
  this.authProvider = authProvider;
148
152
  this.authRequested = true;
153
+ this.pendingResumeSessionId = null;
149
154
  if (this.ws?.readyState === WS_OPEN) {
150
155
  if (this.welcomeReceived && !this.startAuthSent) {
151
156
  await this.sendStartAuth();
@@ -316,6 +321,10 @@ export class ActaWsClient extends TypedEventEmitter {
316
321
  this.send({ type: "Ping" });
317
322
  }
318
323
  }
324
+ resumeAuth(sessionId) {
325
+ this.pendingResumeSessionId = sessionId;
326
+ this.sendResumeAuth(sessionId);
327
+ }
319
328
  doConnect() {
320
329
  if (this.ws) {
321
330
  this.cleanup();
@@ -376,7 +385,7 @@ export class ActaWsClient extends TypedEventEmitter {
376
385
  this.emit("welcome", message.data);
377
386
  this.flushPendingMessages();
378
387
  if (this.authRequested && this.authProvider && !this.startAuthSent) {
379
- void this.sendStartAuth().catch((err) => {
388
+ void this.beginAuthHandshake().catch((err) => {
380
389
  this.emit("error", err);
381
390
  this.setConnectionState("error");
382
391
  });
@@ -401,10 +410,10 @@ export class ActaWsClient extends TypedEventEmitter {
401
410
  void this.handleAuthRequest(message.data.challenge);
402
411
  break;
403
412
  case "AuthSuccess":
404
- this.handleAuthSuccess(message.data.session_id);
413
+ this.handleAuthSuccess(message.data.session_id, message.data.expires_at);
405
414
  break;
406
415
  case "AuthError":
407
- this.handleAuthError(message.data.reason);
416
+ this.handleAuthError(message.data.reason, message.data.message);
408
417
  break;
409
418
  case "Snapshot":
410
419
  this.handleSnapshot(message.data);
@@ -606,6 +615,13 @@ export class ActaWsClient extends TypedEventEmitter {
606
615
  this.setConnectionState("error");
607
616
  }
608
617
  }
618
+ async beginAuthHandshake() {
619
+ if (this.pendingResumeSessionId) {
620
+ this.sendResumeAuth(this.pendingResumeSessionId);
621
+ return;
622
+ }
623
+ await this.sendStartAuth();
624
+ }
609
625
  async sendStartAuth() {
610
626
  if (!this.authProvider)
611
627
  throw new Error("No auth provider configured");
@@ -613,6 +629,10 @@ export class ActaWsClient extends TypedEventEmitter {
613
629
  const pubkey = await this.authProvider.getPublicKey();
614
630
  this.send({ type: "StartAuth", data: { pubkey } });
615
631
  }
632
+ sendResumeAuth(sessionId) {
633
+ this.startAuthSent = true;
634
+ this.send({ type: "ResumeAuth", data: { session_id: sessionId } });
635
+ }
616
636
  sendHello() {
617
637
  const hello = {
618
638
  protocol_version: this.options.protocolVersion,
@@ -631,10 +651,11 @@ export class ActaWsClient extends TypedEventEmitter {
631
651
  this.send(msg);
632
652
  }
633
653
  }
634
- handleAuthSuccess(sessionId) {
654
+ handleAuthSuccess(sessionId, expiresAt) {
635
655
  this.sessionId = sessionId;
656
+ this.pendingResumeSessionId = null;
636
657
  this.setConnectionState("authenticated");
637
- this.emit("authenticated", sessionId);
658
+ this.emit("authenticated", sessionId, expiresAt);
638
659
  if (this.subscribedChannels.size > 0) {
639
660
  const channels = Array.from(this.subscribedChannels);
640
661
  const data = this.hasMarketScope
@@ -643,9 +664,23 @@ export class ActaWsClient extends TypedEventEmitter {
643
664
  this.send({ type: "Subscribe", data });
644
665
  }
645
666
  }
646
- handleAuthError(reason) {
667
+ handleAuthError(reason, message) {
668
+ this.emit("authError", reason);
669
+ if (reason === "session_expired" &&
670
+ this.authRequested &&
671
+ this.authProvider &&
672
+ this.pendingResumeSessionId) {
673
+ this.pendingResumeSessionId = null;
674
+ this.startAuthSent = false;
675
+ void this.sendStartAuth().catch((err) => {
676
+ this.emit("error", err);
677
+ this.setConnectionState("error");
678
+ });
679
+ return;
680
+ }
647
681
  this.setConnectionState("error");
648
- this.emit("error", new Error(`Authentication failed: ${reason}`));
682
+ const details = message ? `${reason}: ${message}` : reason;
683
+ this.emit("error", new Error(`Authentication failed: ${details}`));
649
684
  }
650
685
  handleSnapshot(snapshot) {
651
686
  this.state.stats = snapshot.stats;
@@ -845,6 +880,7 @@ export class ActaWsClient extends TypedEventEmitter {
845
880
  this.helloSent = false;
846
881
  this.welcomeReceived = false;
847
882
  this.startAuthSent = false;
883
+ this.pendingResumeSessionId = null;
848
884
  this.pendingMessages = [];
849
885
  this.setConnectionState("disconnected");
850
886
  }
@@ -119,6 +119,62 @@ describe("ActaWsClient", () => {
119
119
  expect(authChallenge.data.challenge).toBe("challenge-text");
120
120
  }
121
121
  });
122
+ it("connectAndAuthenticate sends ResumeAuth when sessionId is provided", async () => {
123
+ const { client, socket } = makeHarness();
124
+ const auth = makeAuthProvider("WalletPubkey", "WalletSignature");
125
+ client.connectAndAuthenticate(auth, { sessionId: "resume-session-id" });
126
+ const ws = socket();
127
+ ws.triggerOpen();
128
+ ws.triggerMessage(WELCOME_MESSAGE);
129
+ await flushMicrotasks();
130
+ const sentTypes = ws.sent.map((payload) => parseClientMessage(payload).type);
131
+ expect(sentTypes).toEqual(["Hello", "ResumeAuth"]);
132
+ const resumeAuth = parseClientMessage(ws.sent[1]);
133
+ expect(resumeAuth.type).toBe("ResumeAuth");
134
+ if (resumeAuth.type === "ResumeAuth") {
135
+ expect(resumeAuth.data.session_id).toBe("resume-session-id");
136
+ }
137
+ });
138
+ it("falls back to StartAuth when ResumeAuth session_expired", async () => {
139
+ const { client, socket } = makeHarness();
140
+ const auth = makeAuthProvider("WalletPubkey", "WalletSignature");
141
+ client.connectAndAuthenticate(auth, { sessionId: "expired-session" });
142
+ const ws = socket();
143
+ ws.triggerOpen();
144
+ ws.triggerMessage(WELCOME_MESSAGE);
145
+ await flushMicrotasks();
146
+ ws.triggerMessage({
147
+ type: "AuthError",
148
+ data: { reason: "session_expired" },
149
+ });
150
+ await flushMicrotasks();
151
+ const sentTypes = ws.sent.map((payload) => parseClientMessage(payload).type);
152
+ expect(sentTypes).toEqual(["Hello", "ResumeAuth", "StartAuth"]);
153
+ });
154
+ it("emits authenticated with expiresAt from AuthSuccess", () => {
155
+ const { client } = makeHarness();
156
+ const seen = [];
157
+ client.on("authenticated", (sessionId, expiresAt) => {
158
+ seen.push({ sessionId, expiresAt });
159
+ });
160
+ client.handleMessage({
161
+ type: "AuthSuccess",
162
+ data: { session_id: "auth-session", expires_at: 1_710_086_400 },
163
+ });
164
+ expect(seen).toEqual([
165
+ { sessionId: "auth-session", expiresAt: 1_710_086_400 },
166
+ ]);
167
+ });
168
+ it("emits authError reason on AuthError", () => {
169
+ const { client } = makeHarness();
170
+ const reasons = [];
171
+ client.on("authError", (reason) => reasons.push(reason));
172
+ client.handleMessage({
173
+ type: "AuthError",
174
+ data: { reason: "invalid_signature", message: "bad signature bytes" },
175
+ });
176
+ expect(reasons).toEqual(["invalid_signature"]);
177
+ });
122
178
  it("drop_oldest policy keeps the latest queued messages", () => {
123
179
  const { client, socket } = makeHarness({
124
180
  maxPendingMessages: 2,
@@ -78,6 +78,11 @@ export type ClientMessage = {
78
78
  data: {
79
79
  pubkey: string;
80
80
  };
81
+ } | {
82
+ type: "ResumeAuth";
83
+ data: {
84
+ session_id: string;
85
+ };
81
86
  } | {
82
87
  type: "AuthChallenge";
83
88
  data: AuthChallengeData;
@@ -255,11 +260,13 @@ export type ServerMessage = {
255
260
  type: "AuthSuccess";
256
261
  data: {
257
262
  session_id: string;
263
+ expires_at: WsI64 | null;
258
264
  };
259
265
  } | {
260
266
  type: "AuthError";
261
267
  data: {
262
268
  reason: ErrorMessage;
269
+ message?: string;
263
270
  };
264
271
  } | {
265
272
  type: "RfqCreated";
@@ -628,6 +635,8 @@ export type MakerPositionInfo = {
628
635
  strike: WsU64;
629
636
  quantity: WsU64;
630
637
  price: WsU64;
638
+ /** Net premium amount from on-chain position state (quote token base units). */
639
+ total_premium: WsU64;
631
640
  collateral_locked: WsU64;
632
641
  created_at: WsU64;
633
642
  expiry_ts: WsU64;
@@ -813,6 +822,8 @@ export type PositionInfo = {
813
822
  strike: WsU64;
814
823
  quantity: WsU64;
815
824
  price: WsU64;
825
+ /** Net premium amount from on-chain position state (quote token base units). */
826
+ total_premium: WsU64;
816
827
  created_at: WsU64;
817
828
  };
818
829
  export type TradeInfo = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@acta-markets/ts-sdk",
3
- "version": "0.0.1-beta",
3
+ "version": "0.0.3-beta",
4
4
  "description": "TypeScript SDK for Acta Protocol",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",