@depthhq/sdk 0.1.6 → 0.1.8

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/index.d.ts CHANGED
@@ -34,3 +34,4 @@ export { DepthProvider } from "./chain/provider.js";
34
34
  export { authenticateManifest, captureDeployment, manifestBytes, verifyDeployment, } from "./chain/manifest.js";
35
35
  export type { DeploymentManifest, SignedManifest, DeploymentPolicy, } from "./chain/manifest.js";
36
36
  export { ViewSession } from "./view/session.js";
37
+ export { HttpConnection } from "./chain/connection.js";
package/dist/index.js CHANGED
@@ -43622,7 +43622,7 @@ import {
43622
43622
  circuits as circuits2,
43623
43623
  computationName,
43624
43624
  DEPTH_IDL as DEPTH_IDL3,
43625
- DEPTH_PROGRAM_ID as DEPTH_PROGRAM_ID8,
43625
+ DEPTH_PROGRAM_ID as DEPTH_PROGRAM_ID9,
43626
43626
  marketAddress as marketAddress8,
43627
43627
  protocolAddress as protocolAddress4,
43628
43628
  recoveryConfigAddress as recoveryConfigAddress2,
@@ -46676,6 +46676,37 @@ function tradeLimit(input, direction, oraclePriceE8) {
46676
46676
  return price;
46677
46677
  }
46678
46678
 
46679
+ // src/trade/snapshot.ts
46680
+ import { DEPTH_PROGRAM_ID as DEPTH_PROGRAM_ID6 } from "@depthhq/bindings";
46681
+ async function quoteSnapshot(connection, program, address2, initial) {
46682
+ let market = initial;
46683
+ for (let attempt = 0;attempt < 4; attempt++) {
46684
+ const quotes = market.activeQuotes.slice(0, market.activeQuoteCount);
46685
+ const keys = [market.backstopOffer, ...quotes];
46686
+ const [account, ...records] = await connection.getMultipleAccountsInfo([address2, ...keys], "confirmed");
46687
+ if (!account?.owner.equals(DEPTH_PROGRAM_ID6))
46688
+ throw new Error("Market account is unavailable");
46689
+ const latest = program.coder.accounts.decode("market", account.data);
46690
+ if (!latest.backstopOffer.equals(market.backstopOffer) || latest.activeQuoteCount !== quotes.length || latest.activeQuotes.slice(0, latest.activeQuoteCount).some((key, index) => !key.equals(quotes[index]))) {
46691
+ market = latest;
46692
+ continue;
46693
+ }
46694
+ if (market.activeQuoteCount === 0)
46695
+ throw new Error("Waiting for maker liquidity");
46696
+ for (const [index, record] of records.entries()) {
46697
+ if (!record?.owner.equals(DEPTH_PROGRAM_ID6))
46698
+ throw new Error(`Market quote snapshot missing account ${index}`);
46699
+ if (index === 0)
46700
+ continue;
46701
+ const quote = program.coder.accounts.decode("quoteRecord", record.data);
46702
+ if (!("active" in quote.status) || quote.expiry.toNumber() <= Math.floor(Date.now() / 1000) || !quote.market.equals(address2))
46703
+ throw new Error("Waiting for maker liquidity");
46704
+ }
46705
+ return { market: latest, keys };
46706
+ }
46707
+ throw new Error("Market is processing another order");
46708
+ }
46709
+
46679
46710
  // src/trade/flow.ts
46680
46711
  import { transferAddress as transferAddress4 } from "@depthhq/bindings";
46681
46712
 
@@ -46741,7 +46772,7 @@ class TradeFlow {
46741
46772
 
46742
46773
  // src/view/view.ts
46743
46774
  init_buffer();
46744
- import { circuits, DEPTH_PROGRAM_ID as DEPTH_PROGRAM_ID6 } from "@depthhq/bindings";
46775
+ import { circuits, DEPTH_PROGRAM_ID as DEPTH_PROGRAM_ID7 } from "@depthhq/bindings";
46745
46776
  var mask64 = (1n << 64n) - 1n;
46746
46777
  var mask128 = (1n << 128n) - 1n;
46747
46778
  var fillPacker = createPacker([
@@ -46808,7 +46839,7 @@ class DepthView {
46808
46839
  }
46809
46840
  async status() {
46810
46841
  const response = await this.connection.getAccountInfoAndContext(this.id, "confirmed");
46811
- if (!response.value || !response.value.owner.equals(DEPTH_PROGRAM_ID6)) {
46842
+ if (!response.value || !response.value.owner.equals(DEPTH_PROGRAM_ID7)) {
46812
46843
  throw new Error("Private view account is unavailable");
46813
46844
  }
46814
46845
  const state = this.program.coder.accounts.decode(this.kind === "balance" ? "balanceView" : this.kind === "market" ? "marketView" : this.kind === "fill" ? "fillView" : "quoteView", response.value.data);
@@ -46917,7 +46948,7 @@ class DepthView {
46917
46948
  init_buffer();
46918
46949
  import * as anchor8 from "@anchor-lang/core";
46919
46950
  import {
46920
- DEPTH_PROGRAM_ID as DEPTH_PROGRAM_ID7,
46951
+ DEPTH_PROGRAM_ID as DEPTH_PROGRAM_ID8,
46921
46952
  marketAddress as marketAddress7,
46922
46953
  viewPermitAddress
46923
46954
  } from "@depthhq/bindings";
@@ -47140,7 +47171,7 @@ class ViewSession {
47140
47171
  const info = await this.connection.getAccountInfo(keys.permit, "confirmed");
47141
47172
  if (!info)
47142
47173
  return { active: false, id: keys.permit.toBase58() };
47143
- if (!info.owner.equals(DEPTH_PROGRAM_ID7))
47174
+ if (!info.owner.equals(DEPTH_PROGRAM_ID8))
47144
47175
  throw new Error("Invalid private read permission owner");
47145
47176
  const permit = this.program.coder.accounts.decode("viewPermit", info.data);
47146
47177
  const expiresAt = permit.expiresAt.toNumber();
@@ -47193,7 +47224,7 @@ class ViewSession {
47193
47224
  async post(request, action) {
47194
47225
  const { signing } = await this.keys();
47195
47226
  request.expiresAt = Math.floor(Date.now() / 1000) + 120;
47196
- request.signature = Buffer2.from(await sign(new TextEncoder().encode(viewMessage(DEPTH_PROGRAM_ID7.toBase58(), request, action)), signing)).toString("base64");
47227
+ request.signature = Buffer2.from(await sign(new TextEncoder().encode(viewMessage(DEPTH_PROGRAM_ID8.toBase58(), request, action)), signing)).toString("base64");
47197
47228
  return fetch(`${this.serviceUrl}/v1/views${action === "close" ? "/close" : ""}`, {
47198
47229
  method: "POST",
47199
47230
  headers: { "content-type": "application/json" },
@@ -47253,10 +47284,10 @@ class ViewSession {
47253
47284
  payer.toBuffer(),
47254
47285
  nonce
47255
47286
  ];
47256
- const id = PublicKey10.findProgramAddressSync(seeds, DEPTH_PROGRAM_ID7)[0];
47287
+ const id = PublicKey10.findProgramAddressSync(seeds, DEPTH_PROGRAM_ID8)[0];
47257
47288
  if (receipt.id !== id.toBase58() || typeof receipt.signature !== "string")
47258
47289
  throw new Error("Invalid private read receipt");
47259
- const mxeKey = await getMXEPublicKey(this.program.provider, DEPTH_PROGRAM_ID7);
47290
+ const mxeKey = await getMXEPublicKey(this.program.provider, DEPTH_PROGRAM_ID8);
47260
47291
  if (!mxeKey)
47261
47292
  throw new Error("MXE public key is unavailable");
47262
47293
  return new DepthView(id, receipt.signature, kind, payer, keys.secret, keys.viewKey, mxeKey, this.program, this.connection, source, async () => {
@@ -47271,7 +47302,7 @@ class ViewSession {
47271
47302
  }
47272
47303
 
47273
47304
  // src/client/client.ts
47274
- function pda(seeds, programId = DEPTH_PROGRAM_ID8) {
47305
+ function pda(seeds, programId = DEPTH_PROGRAM_ID9) {
47275
47306
  return PublicKey11.findProgramAddressSync(seeds, programId)[0];
47276
47307
  }
47277
47308
  function nonce() {
@@ -47291,7 +47322,7 @@ class DepthClient {
47291
47322
  position;
47292
47323
  marketAddress = marketAddress8();
47293
47324
  protocolAddress = protocolAddress4();
47294
- mxeAddress = getMXEAccAddress(DEPTH_PROGRAM_ID8);
47325
+ mxeAddress = getMXEAccAddress(DEPTH_PROGRAM_ID9);
47295
47326
  get catalog() {
47296
47327
  return new MarketCatalog(this);
47297
47328
  }
@@ -47310,7 +47341,7 @@ class DepthClient {
47310
47341
  }
47311
47342
  constructor(options) {
47312
47343
  this.options = options;
47313
- const scope = `${"manifest" in options.deployment ? options.deployment.manifest.payload.genesisHash : "localnet"}:${DEPTH_PROGRAM_ID8.toBase58()}:${options.wallet.publicKey.toBase58()}`;
47344
+ const scope = `${"manifest" in options.deployment ? options.deployment.manifest.payload.genesisHash : "localnet"}:${DEPTH_PROGRAM_ID9.toBase58()}:${options.wallet.publicKey.toBase58()}`;
47314
47345
  const storage = options.privateViews === "device" && "manifest" in options.deployment && typeof indexedDB !== "undefined" && globalThis.crypto?.subtle ? new DeviceViews : undefined;
47315
47346
  this.viewCache = new ViewCache(scope, storage);
47316
47347
  this.provider = new DepthProvider(options.connection, options.wallet, {
@@ -47335,7 +47366,7 @@ class DepthClient {
47335
47366
  }
47336
47367
  async verifyDeployment() {
47337
47368
  const [programInfo, protocol, market, app, mxe] = await Promise.all([
47338
- this.options.connection.getAccountInfo(DEPTH_PROGRAM_ID8, "confirmed"),
47369
+ this.options.connection.getAccountInfo(DEPTH_PROGRAM_ID9, "confirmed"),
47339
47370
  this.read("Protocol", this.protocolAddress),
47340
47371
  this.read("Market", this.marketAddress),
47341
47372
  this.options.appId ? this.read("AppConfig", appAddress2(this.options.appId)) : Promise.resolve(undefined),
@@ -47343,13 +47374,13 @@ class DepthClient {
47343
47374
  ]);
47344
47375
  if (!programInfo?.executable)
47345
47376
  throw new Error("Depth program is not deployed");
47346
- if (!market.settlementMint.equals(protocol.settlementMint) || !market.vault.equals(protocol.vault) || this.options.appId && !app?.app.equals(this.options.appId) || !mxe.mxeProgramId.equals(DEPTH_PROGRAM_ID8)) {
47377
+ if (!market.settlementMint.equals(protocol.settlementMint) || !market.vault.equals(protocol.vault) || this.options.appId && !app?.app.equals(this.options.appId) || !mxe.mxeProgramId.equals(DEPTH_PROGRAM_ID9)) {
47347
47378
  throw new Error("Depth deployment accounts disagree");
47348
47379
  }
47349
47380
  }
47350
47381
  async read(name2, address2) {
47351
47382
  const info = await this.options.connection.getAccountInfo(address2, "confirmed");
47352
- if (!info || !info.owner.equals(DEPTH_PROGRAM_ID8)) {
47383
+ if (!info || !info.owner.equals(DEPTH_PROGRAM_ID9)) {
47353
47384
  throw new Error(`${name2} account is unavailable`);
47354
47385
  }
47355
47386
  return this.program.coder.accounts.decode(name2[0].toLowerCase() + name2.slice(1), info.data);
@@ -47357,7 +47388,7 @@ class DepthClient {
47357
47388
  async queue(name2, offset2) {
47358
47389
  const mxe = await arciumAccount(this.provider).fetch(this.mxeAddress);
47359
47390
  const cluster = mxe.cluster;
47360
- const definition = getCompDefAccAddress(DEPTH_PROGRAM_ID8, Buffer2.from(getCompDefAccOffset(computationName(name2))).readUInt32LE());
47391
+ const definition = getCompDefAccAddress(DEPTH_PROGRAM_ID9, Buffer2.from(getCompDefAccOffset(computationName(name2))).readUInt32LE());
47361
47392
  const definitionInfo = await this.options.connection.getAccountInfo(definition, "confirmed");
47362
47393
  if (!definitionInfo)
47363
47394
  throw new Error(`${name2} computation is not deployed`);
@@ -47379,7 +47410,7 @@ class DepthClient {
47379
47410
  }
47380
47411
  async market() {
47381
47412
  const response = await this.options.connection.getAccountInfoAndContext(this.marketAddress, "confirmed");
47382
- if (!response.value || !response.value.owner.equals(DEPTH_PROGRAM_ID8)) {
47413
+ if (!response.value || !response.value.owner.equals(DEPTH_PROGRAM_ID9)) {
47383
47414
  throw new Error("Depth market is unavailable");
47384
47415
  }
47385
47416
  return {
@@ -47457,7 +47488,7 @@ class DepthClient {
47457
47488
  const source = accounts2.balance ?? accounts2.marketAccount ?? accounts2.order ?? accounts2.quote;
47458
47489
  if (this.options.viewAuthorization === "session" || this.options.viewAuthorization !== "wallet" && this.options.privateViews === "device" && this.options.serviceUrl)
47459
47490
  return this.views.request(kind, source);
47460
- const mxePublicKey = await getMXEPublicKey(this.provider, DEPTH_PROGRAM_ID8);
47491
+ const mxePublicKey = await getMXEPublicKey(this.provider, DEPTH_PROGRAM_ID9);
47461
47492
  if (!mxePublicKey)
47462
47493
  throw new Error("MXE public key is unavailable");
47463
47494
  const secret = x25519.utils.randomSecretKey();
@@ -47690,7 +47721,7 @@ class DepthClient {
47690
47721
  async deferViewClose(kind, id) {
47691
47722
  const view = new PublicKey11(id);
47692
47723
  const info = await this.options.connection.getAccountInfo(view, "confirmed");
47693
- if (!info?.owner.equals(DEPTH_PROGRAM_ID8))
47724
+ if (!info?.owner.equals(DEPTH_PROGRAM_ID9))
47694
47725
  return;
47695
47726
  const receipt = this.program.coder.accounts.decode(kind === "balance" ? "balanceView" : "marketView", info.data);
47696
47727
  if (!receipt.owner.equals(this.options.wallet.publicKey) || "pending" in receipt.status)
@@ -47842,17 +47873,31 @@ class DepthClient {
47842
47873
  u64(position.collateral, "collateral");
47843
47874
  if (position.collateral === 0n)
47844
47875
  throw new Error("The market account has no collateral");
47845
- const quotes = market.state.activeQuotes.slice(0, market.state.activeQuoteCount);
47846
- if (quotes.length === 0)
47847
- throw new Error("No active maker quote");
47848
- const keys = [market.state.backstopOffer, ...quotes];
47849
- const records = await this.options.connection.getMultipleAccountsInfo(keys, "confirmed");
47850
- records.forEach((info, index) => {
47851
- if (!info?.owner.equals(DEPTH_PROGRAM_ID8)) {
47852
- throw new Error(`Market quote snapshot missing account ${index}`);
47876
+ let keys = [];
47877
+ const quoteDeadline = Date.now() + 60000;
47878
+ for (;; ) {
47879
+ try {
47880
+ const snapshot = await quoteSnapshot(this.options.connection, this.program, this.marketAddress, market.state);
47881
+ market = { ...market, state: snapshot.market };
47882
+ deadline = tradeDeadline(input, Math.floor(Date.now() / 1000), market.state.config.maxOrderQueueSeconds);
47883
+ this.validateTrade(market.state, protocol, account, app, appId, intent, deadline);
47884
+ if (!account.version.eq(new anchor9.BN(position.version.toString())))
47885
+ throw new Error("Private position changed while preparing the trade");
47886
+ keys = snapshot.keys;
47887
+ break;
47888
+ } catch (error) {
47889
+ if (!(error instanceof Error) || ![
47890
+ "Waiting for maker liquidity",
47891
+ "Market is processing another order",
47892
+ "Waiting for a fresh oracle update",
47893
+ "Oracle update is stale"
47894
+ ].includes(error.message) || Date.now() >= quoteDeadline)
47895
+ throw error;
47896
+ [market, protocol, account, app] = await this.waitForMarket(input, appId, intent);
47897
+ await new Promise((resolve) => setTimeout(resolve, 1000));
47853
47898
  }
47854
- });
47855
- const mxePublicKey = await getMXEPublicKey(this.provider, DEPTH_PROGRAM_ID8);
47899
+ }
47900
+ const mxePublicKey = await getMXEPublicKey(this.provider, DEPTH_PROGRAM_ID9);
47856
47901
  if (!mxePublicKey)
47857
47902
  throw new Error("MXE public key is unavailable");
47858
47903
  const secret = x25519.utils.randomSecretKey();
@@ -47909,7 +47954,9 @@ class DepthClient {
47909
47954
  } catch (error) {
47910
47955
  if (!(error instanceof Error) || ![
47911
47956
  "Waiting for maker liquidity",
47912
- "Market is processing another order"
47957
+ "Market is processing another order",
47958
+ "Waiting for a fresh oracle update",
47959
+ "Oracle update is stale"
47913
47960
  ].includes(error.message) || Date.now() >= until)
47914
47961
  throw error;
47915
47962
  }
@@ -47936,6 +47983,8 @@ class DepthClient {
47936
47983
  if (age < 0 || age > market.config.maxOracleAgeSeconds) {
47937
47984
  throw new Error("Oracle update is stale");
47938
47985
  }
47986
+ if (age > market.config.maxOracleAgeSeconds - Math.min(60, Math.floor(market.config.maxOracleAgeSeconds / 2)))
47987
+ throw new Error("Waiting for a fresh oracle update");
47939
47988
  if (deadline <= now || deadline - now > market.config.maxOrderQueueSeconds) {
47940
47989
  throw new Error("Order deadline is outside market policy");
47941
47990
  }
@@ -48099,6 +48148,7 @@ export {
48099
48148
  TradeFlow,
48100
48149
  MarketData,
48101
48150
  MarketCatalog,
48151
+ HttpConnection,
48102
48152
  FundingDiscovery,
48103
48153
  FundingClient,
48104
48154
  ExecutionHistory,
@@ -0,0 +1,7 @@
1
+ import type * as anchor from "@anchor-lang/core";
2
+ import { Connection, PublicKey } from "@solana/web3.js";
3
+ import type { MarketState } from "../client/types.js";
4
+ export declare function quoteSnapshot(connection: Connection, program: anchor.Program, address: PublicKey, initial: MarketState): Promise<{
5
+ market: MarketState;
6
+ keys: anchor.web3.PublicKey[];
7
+ }>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@depthhq/sdk",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -44,7 +44,7 @@
44
44
  "@noble/hashes": "1.8.0",
45
45
  "@solana/web3.js": "1.99.0",
46
46
  "buffer": "6.0.3",
47
- "@depthhq/bindings": "0.1.2",
47
+ "@depthhq/bindings": "0.1.4",
48
48
  "@depthhq/schema": "0.1.2"
49
49
  },
50
50
  "devDependencies": {