@depthhq/sdk 0.1.0 → 0.1.2

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.
@@ -1,5 +1,6 @@
1
1
  import * as anchor from "@anchor-lang/core";
2
2
  import { Connection, PublicKey } from "@solana/web3.js";
3
+ import { type ReceiptTransaction } from "../chain/transaction.js";
3
4
  export type PendingKind = "deposit" | "allocation" | "release" | "withdrawal" | "trade" | "risk";
4
5
  export type PendingItem = {
5
6
  id: PublicKey;
@@ -11,6 +12,9 @@ export type PendingPage = {
11
12
  items: PendingItem[];
12
13
  nextCursor?: string;
13
14
  };
15
+ export type ReceiptDetail = ReceiptTransaction & {
16
+ amount?: bigint;
17
+ };
14
18
  export type UnpairedAllocation = {
15
19
  id: PublicKey;
16
20
  nonce: bigint;
@@ -23,6 +27,8 @@ export declare class FundingDiscovery {
23
27
  private readonly connection;
24
28
  private readonly owner;
25
29
  constructor(program: anchor.Program, connection: Connection, owner: PublicKey);
30
+ transaction(item: PendingItem): Promise<ReceiptDetail>;
31
+ detail(item: PendingItem): Promise<ReceiptDetail>;
26
32
  unpairedAllocations(options?: {
27
33
  cursor?: string;
28
34
  limit?: number;
@@ -0,0 +1,9 @@
1
+ import * as anchor from "@anchor-lang/core";
2
+ import { Connection, PublicKey } from "@solana/web3.js";
3
+ export type AccountState = {
4
+ id: string;
5
+ status: "uninitialized" | "opening" | "ready" | "crediting" | "withdrawing" | "moving" | "claiming";
6
+ version: bigint;
7
+ slot: number;
8
+ };
9
+ export declare function balanceState(program: anchor.Program, connection: Connection, owner: PublicKey, address: PublicKey): Promise<AccountState>;
@@ -18,3 +18,4 @@ export type ResolvedConnection = {
18
18
  environment?: DepthEnvironment;
19
19
  };
20
20
  export declare function resolveConnection(options: ConnectionOptions): Promise<ResolvedConnection>;
21
+ export declare function prepare_depth(options: ConnectionOptions): Promise<ResolvedConnection>;
@@ -32,5 +32,5 @@ export type DeploymentPolicy = {
32
32
  };
33
33
  export declare function manifestBytes(value: unknown): Buffer;
34
34
  export declare function authenticateManifest(signed: SignedManifest, trusted: PublicKey): Promise<void>;
35
- export declare function captureDeployment(provider: anchor.AnchorProvider, version: number, expiresAt: number): Promise<DeploymentManifest>;
36
- export declare function verifyDeployment(provider: anchor.AnchorProvider, policy: DeploymentPolicy): Promise<void>;
35
+ export declare function captureDeployment(provider: Pick<anchor.Provider, "connection">, version: number, expiresAt: number): Promise<DeploymentManifest>;
36
+ export declare function verifyDeployment(provider: Pick<anchor.Provider, "connection">, policy: DeploymentPolicy): Promise<void>;
@@ -0,0 +1,15 @@
1
+ import * as anchor from "@anchor-lang/core";
2
+ import type { Connection, PublicKey, VersionedTransactionResponse } from "@solana/web3.js";
3
+ export type SettlementTransaction = {
4
+ signature: string;
5
+ slot: number;
6
+ orderId: PublicKey;
7
+ timestamp?: number;
8
+ };
9
+ export declare function settlementOrder(transaction: VersionedTransactionResponse, program: anchor.Program): PublicKey | undefined;
10
+ export declare function settlementTransaction(connection: Connection, program: anchor.Program, address: PublicKey, match: {
11
+ orderId: PublicKey;
12
+ } | {
13
+ trader: PublicKey;
14
+ market: PublicKey;
15
+ }): Promise<SettlementTransaction>;
@@ -0,0 +1,12 @@
1
+ import * as anchor from "@anchor-lang/core";
2
+ import type { Connection, PublicKey, VersionedTransactionResponse } from "@solana/web3.js";
3
+ export type ReceiptTransaction = {
4
+ signature: string;
5
+ slot: number;
6
+ timestamp?: number;
7
+ };
8
+ export declare function depthInstructions(transaction: VersionedTransactionResponse, program: anchor.Program): {
9
+ definition: anchor.IdlInstruction;
10
+ accounts: (anchor.web3.PublicKey | undefined)[];
11
+ }[];
12
+ export declare function receiptTransaction(connection: Connection, program: anchor.Program, address: PublicKey, names?: readonly string[]): Promise<ReceiptTransaction>;
@@ -7,6 +7,7 @@ import { FundingDiscovery } from "../account/discovery.js";
7
7
  import { FundingClient } from "../account/funding.js";
8
8
  import { DepthOperation } from "../operation/operation.js";
9
9
  import { DepthRecovery } from "../recovery/recovery.js";
10
+ import { ExecutionHistory } from "../history/history.js";
10
11
  import type { AmountSelector } from "../trade/amount.js";
11
12
  import { TradeFlow } from "../trade/flow.js";
12
13
  import { DepthView } from "../view/view.js";
@@ -24,6 +25,8 @@ export declare class DepthClient {
24
25
  get funding(): FundingClient;
25
26
  get app(): AppAdmin;
26
27
  get recovery(): DepthRecovery;
28
+ private historyClient?;
29
+ get history(): ExecutionHistory;
27
30
  private constructor();
28
31
  static create(options: DepthOptions): Promise<DepthClient>;
29
32
  private verifyDeployment;
@@ -48,6 +51,9 @@ export declare class DepthClient {
48
51
  private withdrawRequest;
49
52
  private accountActions;
50
53
  readonly account: (() => {
54
+ state: () => Promise<import("../account/state.js").AccountState>;
55
+ detail: (item: Parameters<FundingDiscovery["detail"]>[0]) => Promise<import("../account/discovery.js").ReceiptDetail>;
56
+ transaction: (item: Parameters<FundingDiscovery["transaction"]>[0]) => Promise<import("../account/discovery.js").ReceiptDetail>;
51
57
  history: (options?: Parameters<FundingDiscovery["history"]>[0]) => Promise<import("../account/discovery.js").PendingPage>;
52
58
  pending: (options?: Parameters<FundingDiscovery["pending"]>[0]) => Promise<import("../account/discovery.js").PendingPage>;
53
59
  cancelOpen: () => Promise<string>;
@@ -73,6 +79,9 @@ export declare class DepthClient {
73
79
  pollMs?: number;
74
80
  }) => Promise<BalanceSnapshot>;
75
81
  }) & {
82
+ state: () => Promise<import("../account/state.js").AccountState>;
83
+ detail: (item: Parameters<FundingDiscovery["detail"]>[0]) => Promise<import("../account/discovery.js").ReceiptDetail>;
84
+ transaction: (item: Parameters<FundingDiscovery["transaction"]>[0]) => Promise<import("../account/discovery.js").ReceiptDetail>;
76
85
  history: (options?: Parameters<FundingDiscovery["history"]>[0]) => Promise<import("../account/discovery.js").PendingPage>;
77
86
  pending: (options?: Parameters<FundingDiscovery["pending"]>[0]) => Promise<import("../account/discovery.js").PendingPage>;
78
87
  cancelOpen: () => Promise<string>;
@@ -98,5 +98,8 @@ export type OrderState = {
98
98
  status: Record<string, unknown>;
99
99
  kind: Record<string, unknown>;
100
100
  trader: PublicKey;
101
+ maker?: PublicKey;
101
102
  market: PublicKey;
103
+ traderVersion: anchor.BN;
104
+ fundingIndex: anchor.BN;
102
105
  };
@@ -0,0 +1,26 @@
1
+ import * as anchor from "@anchor-lang/core";
2
+ import { Connection, PublicKey } from "@solana/web3.js";
3
+ import type { DepthView, FillSnapshot } from "../view/view.js";
4
+ import { type SettlementTransaction } from "../chain/settlement.js";
5
+ import type { PositionPnl } from "../position/pnl.js";
6
+ export type ExecutionDetail = {
7
+ id: PublicKey;
8
+ fill: FillSnapshot;
9
+ pnl?: PositionPnl;
10
+ transaction: SettlementTransaction;
11
+ };
12
+ export declare class ExecutionHistory {
13
+ private readonly program;
14
+ private readonly connection;
15
+ private readonly owner;
16
+ private readonly requestView;
17
+ private readonly views;
18
+ private readonly fills;
19
+ private readonly transactions;
20
+ constructor(program: anchor.Program, connection: Connection, owner: PublicKey, requestView: (id: PublicKey) => Promise<DepthView>);
21
+ private orderAddress;
22
+ fill(id: PublicKey): Promise<FillSnapshot>;
23
+ execution(nonce: bigint): Promise<ExecutionDetail>;
24
+ private settlement;
25
+ private scan;
26
+ }
@@ -0,0 +1,13 @@
1
+ import type { FillSnapshot } from "../view/view.js";
2
+ import { type PositionPnl } from "../position/pnl.js";
3
+ export type ReplayState = {
4
+ position: bigint;
5
+ entryPriceE8: bigint;
6
+ fundingCheckpoint: bigint;
7
+ collateral?: bigint;
8
+ };
9
+ export declare function replayFill(state: ReplayState, fill: FillSnapshot, fundingIndex: bigint, maker?: boolean): {
10
+ state: ReplayState;
11
+ pnl?: PositionPnl;
12
+ };
13
+ export declare function replayMargin(state: ReplayState, amount: bigint, toMarket: boolean): ReplayState;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,11 @@
1
1
  export { DepthClient, createDepth, createDepth as create_depth, } from "./client/client.js";
2
2
  export { DepthOperation } from "./operation/operation.js";
3
+ export { ExecutionHistory } from "./history/history.js";
4
+ export type { ExecutionDetail } from "./history/history.js";
5
+ export type { PositionPnl } from "./position/pnl.js";
6
+ export { positionPnl } from "./position/pnl.js";
7
+ export type { SettlementTransaction } from "./chain/settlement.js";
8
+ export type { ReceiptTransaction } from "./chain/transaction.js";
3
9
  export { TradeFlow } from "./trade/flow.js";
4
10
  export type { TradeFlowSnapshot } from "./trade/flow.js";
5
11
  export { MarketCatalog } from "./catalog/catalog.js";
@@ -9,6 +15,7 @@ export type { DataOptions, CandleQuery } from "./catalog/data.js";
9
15
  export type { Candle, CandleInterval, CandlePage, PublicMarket, PublicApp, } from "@depthhq/schema";
10
16
  export { AppAdmin, AppRegistration, AppUpdate } from "./app/app.js";
11
17
  export { FundingDiscovery } from "./account/discovery.js";
18
+ export type { ReceiptDetail } from "./account/discovery.js";
12
19
  export type { PendingItem, PendingKind, PendingPage, UnpairedAllocation, } from "./account/discovery.js";
13
20
  export type { AppSummary } from "./app/app.js";
14
21
  export { DepthRecovery } from "./recovery/recovery.js";
@@ -19,7 +26,8 @@ export { resolveAmount } from "./trade/amount.js";
19
26
  export type { AmountSelector } from "./trade/amount.js";
20
27
  export type { BalanceSnapshot, FillSnapshot, PositionSnapshot, QuoteBalanceSnapshot, } from "./view/view.js";
21
28
  export type { DepthOptions, DepthWallet, TradeInput, ReductionInput, CloseInput, ReverseInput, TradeIntent, } from "./client/types.js";
22
- export { resolveConnection } from "./chain/environment.js";
29
+ export { resolveConnection, prepare_depth } from "./chain/environment.js";
30
+ export type { AccountState } from "./account/state.js";
23
31
  export type { ConnectionOptions, ResolvedConnection, DepthEnvironment, } from "./chain/environment.js";
24
32
  export { DepthError } from "./operation/error.js";
25
33
  export { DepthProvider } from "./chain/provider.js";
package/dist/index.js CHANGED
@@ -18122,7 +18122,7 @@ https://github.com/browserify/crypto-browserify`);
18122
18122
 
18123
18123
  // src/client/client.ts
18124
18124
  init_buffer();
18125
- import * as anchor6 from "@anchor-lang/core";
18125
+ import * as anchor8 from "@anchor-lang/core";
18126
18126
 
18127
18127
  // ../../node_modules/@noble/hashes/esm/crypto.js
18128
18128
  var crypto2 = typeof globalThis === "object" && "crypto" in globalThis ? globalThis.crypto : undefined;
@@ -43623,12 +43623,12 @@ import {
43623
43623
  computationName,
43624
43624
  DEPTH_IDL as DEPTH_IDL3,
43625
43625
  DEPTH_PROGRAM_ID as DEPTH_PROGRAM_ID7,
43626
- marketAddress as marketAddress6,
43626
+ marketAddress as marketAddress7,
43627
43627
  protocolAddress as protocolAddress4,
43628
43628
  recoveryConfigAddress as recoveryConfigAddress2,
43629
43629
  SOL_USD_MARKET_ID as SOL_USD_MARKET_ID3
43630
43630
  } from "@depthhq/bindings";
43631
- import { PublicKey as PublicKey8 } from "@solana/web3.js";
43631
+ import { PublicKey as PublicKey9 } from "@solana/web3.js";
43632
43632
 
43633
43633
  // src/chain/random.ts
43634
43634
  function randomBytes3(length) {
@@ -44491,7 +44491,7 @@ async function captureDeployment(provider, version, expiresAt) {
44491
44491
  const protocol = coder.decode("protocol", protocolInfo.data);
44492
44492
  if (!market.settlementMint.equals(protocol.settlementMint))
44493
44493
  throw new Error("Deployment settlement mints disagree");
44494
- const arcium2 = getArciumProgram(provider);
44494
+ const arcium2 = new anchor2.Program(ARCIUM_IDL, provider);
44495
44495
  const mxeAddress = getMXEAccAddress(DEPTH_PROGRAM_ID);
44496
44496
  const mxe = await arcium2.account.mxeAccount.fetch(mxeAddress);
44497
44497
  if (!mxe.mxeProgramId.equals(DEPTH_PROGRAM_ID))
@@ -44521,6 +44521,7 @@ async function captureDeployment(provider, version, expiresAt) {
44521
44521
  })
44522
44522
  };
44523
44523
  }
44524
+ var verified = new WeakMap;
44524
44525
  async function verifyDeployment(provider, policy) {
44525
44526
  if ("localnet" in policy) {
44526
44527
  const url = new URL(provider.connection.rpcEndpoint);
@@ -44530,9 +44531,28 @@ async function verifyDeployment(provider, policy) {
44530
44531
  }
44531
44532
  await authenticateManifest(policy.manifest, policy.trustedSigner);
44532
44533
  const expected = policy.manifest.payload;
44533
- const actual = await captureDeployment(provider, expected.version, expected.expiresAt);
44534
- if (!manifestBytes(actual).equals(manifestBytes(expected)))
44535
- throw new Error("Signed deployment does not match the connected chain");
44534
+ const key = manifestBytes(policy.manifest).toString("base64");
44535
+ const previous = verified.get(provider.connection);
44536
+ if (previous?.key === key && previous.expiresAt > Date.now())
44537
+ return previous.task;
44538
+ const task = (async () => {
44539
+ const actual = await captureDeployment(provider, expected.version, expected.expiresAt);
44540
+ if (!manifestBytes(actual).equals(manifestBytes(expected)))
44541
+ throw new Error("Signed deployment does not match the connected chain");
44542
+ })();
44543
+ const entry = {
44544
+ key,
44545
+ expiresAt: Math.min(Date.now() + 30000, expected.expiresAt * 1000),
44546
+ task
44547
+ };
44548
+ verified.set(provider.connection, entry);
44549
+ try {
44550
+ await task;
44551
+ } catch (error) {
44552
+ if (verified.get(provider.connection) === entry)
44553
+ verified.delete(provider.connection);
44554
+ throw error;
44555
+ }
44536
44556
  }
44537
44557
 
44538
44558
  // src/chain/network.ts
@@ -44625,7 +44645,7 @@ async function upgradeAuthority(connection) {
44625
44645
  if (!program?.executable || !program.owner.equals(loader) || program.data.length !== 36 || program.data.readUInt32LE(0) !== 2) {
44626
44646
  throw unavailable("Depth program is not deployed as an upgradeable program");
44627
44647
  }
44628
- const data = await connection.getAccountInfo(new PublicKey3(program.data.subarray(4)), "confirmed");
44648
+ const data = await connection.getAccountInfo(new PublicKey3(program.data.subarray(4)), { commitment: "confirmed", dataSlice: { offset: 0, length: 45 } });
44629
44649
  if (!data?.owner.equals(loader) || data.data.length < 45 || data.data.readUInt32LE(0) !== 3 || data.data[12] !== 1) {
44630
44650
  throw unavailable("Depth deployment has no verifiable upgrade authority");
44631
44651
  }
@@ -44687,6 +44707,11 @@ async function resolveConnection(options) {
44687
44707
  throw unavailable("Depth deployment could not be verified", error);
44688
44708
  }
44689
44709
  }
44710
+ async function prepare_depth(options) {
44711
+ const resolved = await resolveConnection(options);
44712
+ await verifyDeployment({ connection: resolved.connection }, resolved.deployment);
44713
+ return resolved;
44714
+ }
44690
44715
 
44691
44716
  // src/chain/arcium.ts
44692
44717
  function arciumAccount(provider) {
@@ -44999,6 +45024,124 @@ import {
44999
45024
  withdrawalAddress
45000
45025
  } from "@depthhq/bindings";
45001
45026
  import { PublicKey as PublicKey4 } from "@solana/web3.js";
45027
+
45028
+ // src/chain/transaction.ts
45029
+ init_buffer();
45030
+ import * as anchor4 from "@anchor-lang/core";
45031
+ function depthInstructions(transaction, program) {
45032
+ if (!transaction.meta || transaction.meta.err)
45033
+ return [];
45034
+ const keys = transaction.transaction.message.getAccountKeys({
45035
+ accountKeysFromLookups: transaction.meta.loadedAddresses
45036
+ });
45037
+ const instructions2 = [
45038
+ ...transaction.transaction.message.compiledInstructions.map((ix) => ({
45039
+ programIdIndex: ix.programIdIndex,
45040
+ accounts: ix.accountKeyIndexes,
45041
+ data: Buffer2.from(ix.data)
45042
+ })),
45043
+ ...(transaction.meta.innerInstructions ?? []).flatMap((group) => group.instructions.map((ix) => ({
45044
+ programIdIndex: ix.programIdIndex,
45045
+ accounts: ix.accounts,
45046
+ data: Buffer2.from(anchor4.utils.bytes.bs58.decode(ix.data))
45047
+ })))
45048
+ ];
45049
+ return instructions2.flatMap((ix) => {
45050
+ if (!keys.get(ix.programIdIndex)?.equals(program.programId))
45051
+ return [];
45052
+ let definition = program.idl.instructions.find((item) => ix.data.subarray(0, 8).equals(Buffer2.from(item.discriminator)));
45053
+ if (!definition && ix.data.subarray(0, 8).equals(Buffer2.from("057da1a57b4b7ec6", "hex"))) {
45054
+ const current = program.idl.instructions.find((item) => item.name === "debitMarketV2Callback");
45055
+ if (current)
45056
+ definition = { ...current, name: "debitMarketCallback" };
45057
+ }
45058
+ return definition ? [{ definition, accounts: ix.accounts.map((index) => keys.get(index)) }] : [];
45059
+ });
45060
+ }
45061
+ async function receiptTransaction(connection, program, address2, names) {
45062
+ let before;
45063
+ for (let page = 0;page < 10; page++) {
45064
+ const signatures = await connection.getSignaturesForAddress(address2, { before, limit: 50 }, "confirmed");
45065
+ for (const signature of signatures) {
45066
+ if (signature.err)
45067
+ continue;
45068
+ const transaction = await connection.getTransaction(signature.signature, {
45069
+ commitment: "confirmed",
45070
+ maxSupportedTransactionVersion: 0
45071
+ });
45072
+ if (!transaction)
45073
+ throw new Error("Transaction history is unavailable; retry with an archival RPC");
45074
+ const changed = depthInstructions(transaction, program).some((ix) => (!names || names.includes(ix.definition.name)) && ix.definition.accounts.some((account, index) => ("writable" in account) && account.writable && ix.accounts[index]?.equals(address2)));
45075
+ if (changed)
45076
+ return {
45077
+ signature: signature.signature,
45078
+ slot: signature.slot,
45079
+ ...transaction.blockTime == null ? {} : { timestamp: transaction.blockTime }
45080
+ };
45081
+ }
45082
+ if (signatures.length < 50)
45083
+ break;
45084
+ before = signatures.at(-1).signature;
45085
+ }
45086
+ throw new Error(`Receipt transaction for ${address2.toBase58()} was not found in recent history`);
45087
+ }
45088
+
45089
+ // src/chain/settlement.ts
45090
+ function settlementOrder(transaction, program) {
45091
+ const instruction = depthInstructions(transaction, program).find((ix) => ix.definition.name === "sealClearingCallback");
45092
+ if (!instruction)
45093
+ return;
45094
+ const orderIndex = instruction.definition.accounts.findIndex((account) => account.name === "order");
45095
+ if (orderIndex < 0)
45096
+ throw new Error("Settlement callback has no order account");
45097
+ return instruction.accounts[orderIndex];
45098
+ }
45099
+ async function settlementTransaction(connection, program, address2, match) {
45100
+ let before;
45101
+ for (let page = 0;page < 10; page++) {
45102
+ const signatures = await connection.getSignaturesForAddress(address2, { before, limit: 50 }, "confirmed");
45103
+ for (const signature of signatures) {
45104
+ if (signature.err)
45105
+ continue;
45106
+ const transaction = await connection.getTransaction(signature.signature, {
45107
+ commitment: "confirmed",
45108
+ maxSupportedTransactionVersion: 0
45109
+ });
45110
+ if (!transaction)
45111
+ throw new Error("Transaction history is unavailable; retry with an archival RPC");
45112
+ const orderId = settlementOrder(transaction, program);
45113
+ if (!orderId)
45114
+ continue;
45115
+ if ("orderId" in match) {
45116
+ if (orderId.equals(match.orderId))
45117
+ return {
45118
+ signature: signature.signature,
45119
+ slot: signature.slot,
45120
+ orderId,
45121
+ ...transaction.blockTime == null ? {} : { timestamp: transaction.blockTime }
45122
+ };
45123
+ } else {
45124
+ const info = await connection.getAccountInfo(orderId, "confirmed");
45125
+ if (!info?.owner.equals(program.programId))
45126
+ throw new Error("Settlement receipt is unavailable");
45127
+ const order = program.coder.accounts.decode("orderRecord", info.data);
45128
+ if (order.trader.equals(match.trader) && order.market.equals(match.market) && "trade" in order.kind && "filled" in order.status)
45129
+ return {
45130
+ signature: signature.signature,
45131
+ slot: signature.slot,
45132
+ orderId,
45133
+ ...transaction.blockTime == null ? {} : { timestamp: transaction.blockTime }
45134
+ };
45135
+ }
45136
+ }
45137
+ if (signatures.length < 50)
45138
+ break;
45139
+ before = signatures.at(-1).signature;
45140
+ }
45141
+ throw new Error("Settlement transaction was not found in recent history");
45142
+ }
45143
+
45144
+ // src/account/discovery.ts
45002
45145
  function status(state) {
45003
45146
  return Object.keys(state.status)[0] ?? "unknown";
45004
45147
  }
@@ -45012,6 +45155,28 @@ class FundingDiscovery {
45012
45155
  this.connection = connection;
45013
45156
  this.owner = owner;
45014
45157
  }
45158
+ async transaction(item) {
45159
+ return this.detail(item);
45160
+ }
45161
+ async detail(item) {
45162
+ const name2 = item.kind === "deposit" ? "depositReceipt" : item.kind === "withdrawal" ? "withdrawalReceipt" : item.kind === "allocation" || item.kind === "release" ? "marginTransfer" : "orderRecord";
45163
+ const info = await this.connection.getAccountInfo(item.id, "confirmed");
45164
+ if (!info?.owner.equals(this.program.programId))
45165
+ throw new Error("Receipt is unavailable");
45166
+ const state = this.program.coder.accounts.decode(name2, info.data);
45167
+ const canonical = this.project(name2, item.id, state, true);
45168
+ if (!canonical || canonical.kind !== item.kind || canonical.nonce !== item.nonce)
45169
+ throw new Error("Receipt does not match this wallet and operation");
45170
+ if ((canonical.kind === "trade" || canonical.kind === "risk") && canonical.status === "filled")
45171
+ return settlementTransaction(this.connection, this.program, item.id, {
45172
+ orderId: item.id
45173
+ });
45174
+ const transaction = await receiptTransaction(this.connection, this.program, item.id);
45175
+ return {
45176
+ ...transaction,
45177
+ ...state.amount === undefined ? {} : { amount: BigInt(state.amount.toString()) }
45178
+ };
45179
+ }
45015
45180
  async unpairedAllocations(options = {}) {
45016
45181
  const limit = options.limit ?? 20;
45017
45182
  if (!Number.isSafeInteger(limit) || limit < 1 || limit > 100)
@@ -45216,7 +45381,7 @@ class FundingDiscovery {
45216
45381
  }
45217
45382
 
45218
45383
  // src/account/funding.ts
45219
- import * as anchor5 from "@anchor-lang/core";
45384
+ import * as anchor6 from "@anchor-lang/core";
45220
45385
  import {
45221
45386
  balanceAddress,
45222
45387
  depositAddress as depositAddress2,
@@ -45246,7 +45411,7 @@ async function confirmReceipt(id, status2, advance, options = {}) {
45246
45411
  }
45247
45412
 
45248
45413
  // src/trade/input.ts
45249
- import * as anchor4 from "@anchor-lang/core";
45414
+ import * as anchor5 from "@anchor-lang/core";
45250
45415
  function encodeSide(direction) {
45251
45416
  if (direction !== "long" && direction !== "short")
45252
45417
  throw new RangeError("Direction must be long or short");
@@ -45256,12 +45421,12 @@ function u64(value2, name2) {
45256
45421
  if (typeof value2 !== "bigint" || value2 < 0n || value2 > (1n << 64n) - 1n) {
45257
45422
  throw new RangeError(`${name2} must be an unsigned 64-bit bigint`);
45258
45423
  }
45259
- return new anchor4.BN(value2.toString());
45424
+ return new anchor5.BN(value2.toString());
45260
45425
  }
45261
45426
 
45262
45427
  // src/account/funding.ts
45263
45428
  function offset() {
45264
- return new anchor5.BN(randomBytes3(8), "le");
45429
+ return new anchor6.BN(randomBytes3(8), "le");
45265
45430
  }
45266
45431
  function status2(value2) {
45267
45432
  return Object.keys(value2)[0] ?? "unknown";
@@ -45687,6 +45852,34 @@ class WithdrawalHandle {
45687
45852
  }
45688
45853
  }
45689
45854
 
45855
+ // src/account/state.ts
45856
+ async function balanceState(program, connection, owner, address2) {
45857
+ const { context, value: value2 } = await connection.getAccountInfoAndContext(address2, "confirmed");
45858
+ const base = { id: address2.toBase58(), slot: context.slot };
45859
+ if (!value2)
45860
+ return { ...base, status: "uninitialized", version: 0n };
45861
+ if (!value2.owner.equals(program.programId))
45862
+ throw new Error("Balance account is not owned by Depth");
45863
+ const state = program.coder.accounts.decode("balanceAccount", value2.data);
45864
+ if (!state.owner.equals(owner))
45865
+ throw new Error("Balance account does not belong to this wallet");
45866
+ const status3 = Object.keys(state.status)[0];
45867
+ if (![
45868
+ "opening",
45869
+ "ready",
45870
+ "crediting",
45871
+ "withdrawing",
45872
+ "moving",
45873
+ "claiming"
45874
+ ].includes(status3))
45875
+ throw new Error("Balance account has an invalid status");
45876
+ return {
45877
+ ...base,
45878
+ status: status3,
45879
+ version: BigInt(state.version.toString())
45880
+ };
45881
+ }
45882
+
45690
45883
  // src/account/token.ts
45691
45884
  init_buffer();
45692
45885
  import {
@@ -45770,6 +45963,42 @@ import {
45770
45963
  SOL_USD_MARKET_ID as SOL_USD_MARKET_ID2
45771
45964
  } from "@depthhq/bindings";
45772
45965
  import { PublicKey as PublicKey6 } from "@solana/web3.js";
45966
+
45967
+ // src/position/pnl.ts
45968
+ var scale = 100000000000n;
45969
+ function positionPnl(position, priceE8, fundingIndex, fill) {
45970
+ if (position.status !== "ready" || position.position === undefined || position.position === 0n || position.entryPriceE8 === undefined || position.fundingCheckpoint === undefined || position.collateral !== undefined && position.collateral < 0n || priceE8 <= 0n)
45971
+ throw new Error("A ready open position and a positive price are required");
45972
+ const size = position.position < 0n ? -position.position : position.position;
45973
+ const sign = position.position > 0n ? 1n : -1n;
45974
+ let closing = size;
45975
+ let fee = 0n;
45976
+ let state = "open";
45977
+ if (fill) {
45978
+ if (fill.status !== "ready" || fill.side !== -sign || fill.size === undefined || fill.size <= 0n || fill.executionPriceE8 !== priceE8 || fill.fee === undefined || fill.fee < 0n)
45979
+ throw new Error("A ready opposite-side execution is required");
45980
+ closing = fill.size < size ? fill.size : size;
45981
+ fee = fill.fee;
45982
+ state = fill.size === size ? "closed" : fill.size < size ? "reduced" : "reversed";
45983
+ }
45984
+ const gross = sign * closing * (priceE8 - position.entryPriceE8) / scale;
45985
+ const funding = position.position * (fundingIndex - position.fundingCheckpoint) / scale;
45986
+ const net = gross - funding - fee;
45987
+ return {
45988
+ side: sign > 0n ? "long" : "short",
45989
+ state,
45990
+ entryPriceE8: position.entryPriceE8,
45991
+ priceE8,
45992
+ collateral: position.collateral ?? null,
45993
+ gross,
45994
+ funding,
45995
+ fee,
45996
+ net,
45997
+ returnBps: position.collateral !== undefined && position.collateral > 0n ? net * 10000n / position.collateral : null
45998
+ };
45999
+ }
46000
+
46001
+ // src/operation/operation.ts
45773
46002
  function enumName(value2) {
45774
46003
  return Object.keys(value2)[0] ?? "unknown";
45775
46004
  }
@@ -45780,15 +46009,40 @@ class DepthOperation {
45780
46009
  program;
45781
46010
  connection;
45782
46011
  requestFillView;
46012
+ priorPosition;
46013
+ historicalPnl;
45783
46014
  viewPromise;
45784
46015
  view;
45785
46016
  fill;
45786
- constructor(id, signature, program, connection, requestFillView) {
46017
+ settlement;
46018
+ constructor(id, signature, program, connection, requestFillView, priorPosition, historicalPnl) {
45787
46019
  this.id = id;
45788
46020
  this.signature = signature;
45789
46021
  this.program = program;
45790
46022
  this.connection = connection;
45791
46023
  this.requestFillView = requestFillView;
46024
+ this.priorPosition = priorPosition;
46025
+ this.historicalPnl = historicalPnl;
46026
+ }
46027
+ async transaction() {
46028
+ if (this.settlement)
46029
+ return this.settlement;
46030
+ const snapshot = await this.status();
46031
+ if (snapshot.status !== "finalized" || snapshot.outcome !== "filled")
46032
+ throw new Error("Confirm the trade before reading its settlement transaction");
46033
+ this.settlement = await settlementTransaction(this.connection, this.program, this.id, { orderId: this.id });
46034
+ return this.settlement;
46035
+ }
46036
+ async pnl() {
46037
+ if (!this.priorPosition && this.historicalPnl)
46038
+ return this.historicalPnl();
46039
+ const { order } = await this.readOrder();
46040
+ if (!this.priorPosition || this.priorPosition.version !== BigInt(order.traderVersion.toString()))
46041
+ throw new Error("The private position before this execution is unavailable");
46042
+ const fill = await this.privateResult();
46043
+ if (fill.executionPriceE8 === undefined)
46044
+ throw new Error("Execution price is unavailable");
46045
+ return positionPnl(this.priorPosition, fill.executionPriceE8, BigInt(order.fundingIndex.toString()), fill);
45792
46046
  }
45793
46047
  async readOrder() {
45794
46048
  const response = await this.connection.getAccountInfoAndContext(this.id, "confirmed");
@@ -46066,6 +46320,240 @@ class DepthRecovery {
46066
46320
  }
46067
46321
  }
46068
46322
 
46323
+ // src/history/history.ts
46324
+ init_buffer();
46325
+ import * as anchor7 from "@anchor-lang/core";
46326
+ import {
46327
+ accountOffsets as accountOffsets2,
46328
+ marketAddress as marketAddress6,
46329
+ transferAddress as transferAddress3
46330
+ } from "@depthhq/bindings";
46331
+ import { PublicKey as PublicKey8 } from "@solana/web3.js";
46332
+
46333
+ // src/history/replay.ts
46334
+ function replayFill(state, fill, fundingIndex, maker = false) {
46335
+ if (fill.status !== "ready" || fill.side !== 1n && fill.side !== -1n || fill.size === undefined || fill.size <= 0n || fill.executionPriceE8 === undefined || fill.executionPriceE8 <= 0n || fill.fee === undefined || fill.fee < 0n || maker && (fill.makerRebate === undefined || fill.makerRebate < 0n))
46336
+ throw new Error("A complete private execution is required for history");
46337
+ const side = maker ? -fill.side : fill.side;
46338
+ const delta = side * fill.size;
46339
+ const old = state.position;
46340
+ const next = old + delta;
46341
+ const absolute = (value2) => value2 < 0n ? -value2 : value2;
46342
+ const closing = old !== 0n && old > 0n !== delta > 0n;
46343
+ const size = closing ? fill.size < absolute(old) ? fill.size : absolute(old) : 0n;
46344
+ const gross = (old > 0n ? 1n : -1n) * size * (fill.executionPriceE8 - state.entryPriceE8) / 100000000000n;
46345
+ const funding = old * (fundingIndex - state.fundingCheckpoint) / 100000000000n;
46346
+ const fee = maker ? -fill.makerRebate : fill.fee;
46347
+ const cash = gross - funding - fee;
46348
+ const collateral = state.collateral === undefined ? undefined : state.collateral + cash;
46349
+ if (collateral !== undefined && collateral < 0n)
46350
+ throw new Error("Execution history does not conserve collateral");
46351
+ const entryPriceE8 = next === 0n ? 0n : old === 0n || old > 0n !== next > 0n ? fill.executionPriceE8 : closing ? state.entryPriceE8 : (absolute(old) * state.entryPriceE8 + fill.size * fill.executionPriceE8) / absolute(next);
46352
+ let pnl;
46353
+ if (closing) {
46354
+ const position = {
46355
+ id: "history",
46356
+ status: "ready",
46357
+ slot: fill.slot,
46358
+ version: 0n,
46359
+ ...state
46360
+ };
46361
+ pnl = positionPnl(position, fill.executionPriceE8, fundingIndex, {
46362
+ ...fill,
46363
+ side,
46364
+ fee: maker ? 0n : fee
46365
+ });
46366
+ if (maker) {
46367
+ pnl = {
46368
+ ...pnl,
46369
+ fee,
46370
+ net: cash,
46371
+ returnBps: state.collateral !== undefined && state.collateral > 0n ? cash * 10000n / state.collateral : null
46372
+ };
46373
+ }
46374
+ }
46375
+ return {
46376
+ state: {
46377
+ position: next,
46378
+ entryPriceE8,
46379
+ fundingCheckpoint: fundingIndex,
46380
+ collateral
46381
+ },
46382
+ pnl
46383
+ };
46384
+ }
46385
+ function replayMargin(state, amount, toMarket) {
46386
+ if (amount < 0n)
46387
+ throw new Error("Margin history contains a negative amount");
46388
+ const collateral = state.collateral === undefined ? undefined : state.collateral + (toMarket ? amount : -amount);
46389
+ if (collateral !== undefined && collateral < 0n)
46390
+ throw new Error("Margin history does not conserve collateral");
46391
+ return { ...state, collateral };
46392
+ }
46393
+
46394
+ // src/history/history.ts
46395
+ class ExecutionHistory {
46396
+ program;
46397
+ connection;
46398
+ owner;
46399
+ requestView;
46400
+ views = new Map;
46401
+ fills = new Map;
46402
+ transactions = new Map;
46403
+ constructor(program, connection, owner, requestView) {
46404
+ this.program = program;
46405
+ this.connection = connection;
46406
+ this.owner = owner;
46407
+ this.requestView = requestView;
46408
+ }
46409
+ orderAddress(trader, nonce) {
46410
+ return PublicKey8.findProgramAddressSync([
46411
+ Buffer2.from("order"),
46412
+ marketAddress6(this.program.programId).toBuffer(),
46413
+ trader.toBuffer(),
46414
+ nonce.toArrayLike(Buffer2, "le", 8)
46415
+ ], this.program.programId)[0];
46416
+ }
46417
+ async fill(id) {
46418
+ const key = id.toBase58();
46419
+ if (this.fills.has(key) && !this.views.has(key))
46420
+ return this.fills.get(key);
46421
+ if (!this.views.has(key))
46422
+ this.views.set(key, this.requestView(id));
46423
+ let view;
46424
+ try {
46425
+ view = await this.views.get(key);
46426
+ } catch (error) {
46427
+ this.views.delete(key);
46428
+ throw error;
46429
+ }
46430
+ const result = this.fills.get(key) ?? await view.wait({ timeoutMs: 180000 });
46431
+ if (result.status === "stale") {
46432
+ await view.close();
46433
+ this.views.delete(key);
46434
+ throw new Error("Historical private execution changed; retry with the same wallet");
46435
+ }
46436
+ if (result.status !== "ready")
46437
+ throw new Error("Historical private execution is still pending; retry with the same wallet");
46438
+ this.fills.set(key, result);
46439
+ try {
46440
+ await view.close();
46441
+ } catch (error) {
46442
+ if (await this.connection.getAccountInfo(view.id, "confirmed"))
46443
+ throw error;
46444
+ }
46445
+ this.views.delete(key);
46446
+ return result;
46447
+ }
46448
+ async execution(nonce) {
46449
+ if (nonce < 0n || nonce > (1n << 64n) - 1n)
46450
+ throw new RangeError("Trade nonce is invalid");
46451
+ const target = this.orderAddress(this.owner, new anchor7.BN(nonce.toString()));
46452
+ const market = marketAddress6(this.program.programId);
46453
+ const scans = await Promise.all([
46454
+ this.scan("orderRecord", accountOffsets2.OrderRecord.trader),
46455
+ this.scan("orderRecord", accountOffsets2.OrderRecord.maker),
46456
+ this.scan("marginTransfer", accountOffsets2.MarginTransfer.owner)
46457
+ ]);
46458
+ const orders = new Map;
46459
+ for (const account of [...scans[0], ...scans[1]]) {
46460
+ const state2 = this.program.coder.accounts.decode("orderRecord", account.account.data);
46461
+ if (!state2.market.equals(market) || !state2.trader.equals(this.owner) && !state2.maker.equals(this.owner) || !account.pubkey.equals(this.orderAddress(state2.trader, state2.nonce)))
46462
+ throw new Error("Historical order identity is invalid");
46463
+ if ("filled" in state2.status)
46464
+ orders.set(account.pubkey.toBase58(), { id: account.pubkey, state: state2 });
46465
+ }
46466
+ const selected = orders.get(target.toBase58());
46467
+ if (!selected || !("trade" in selected.state.kind) || !selected.state.trader.equals(this.owner))
46468
+ throw new Error("Historical trade is not a filled execution by this wallet");
46469
+ const targetTx = await this.settlement(target);
46470
+ const events2 = [];
46471
+ for (const order of orders.values()) {
46472
+ const version = order.state.trader.equals(this.owner) ? order.state.traderVersion : order.state.makerVersion;
46473
+ if (version && selected.state.traderVersion && version.gt(selected.state.traderVersion))
46474
+ continue;
46475
+ const transaction = order.id.equals(target) ? targetTx : await this.settlement(order.id);
46476
+ if (transaction.slot <= targetTx.slot)
46477
+ events2.push({ id: order.id, order: order.state, transaction });
46478
+ }
46479
+ for (const account of scans[2]) {
46480
+ const state2 = this.program.coder.accounts.decode("marginTransfer", account.account.data);
46481
+ if (!state2.owner.equals(this.owner) || !state2.market.equals(market) || !account.pubkey.equals(transferAddress3(this.owner, BigInt(state2.nonce.toString()), this.program.programId)))
46482
+ throw new Error("Historical margin identity is invalid");
46483
+ if (!("settled" in state2.status) && (state2.toMarket || !("escrow" in state2.status) && !("crediting" in state2.status)) || state2.amount.isZero())
46484
+ continue;
46485
+ const key = account.pubkey.toBase58();
46486
+ const transaction = this.transactions.get(key) ?? await receiptTransaction(this.connection, this.program, account.pubkey, state2.toMarket ? ["creditMarketCallback"] : ["debitMarketV2Callback", "debitMarketCallback"]);
46487
+ this.transactions.set(key, transaction);
46488
+ if (transaction.slot <= targetTx.slot)
46489
+ events2.push({ id: account.pubkey, transfer: state2, transaction });
46490
+ }
46491
+ const indexes = new Map;
46492
+ const counts = new Map;
46493
+ for (const event of events2)
46494
+ counts.set(event.transaction.slot, (counts.get(event.transaction.slot) ?? 0) + 1);
46495
+ for (const [slot, count] of counts)
46496
+ if (count > 1) {
46497
+ const block = await this.connection.getBlockSignatures(slot, "confirmed");
46498
+ if (!block)
46499
+ throw new Error("Block ordering is unavailable; use an archival RPC for execution history");
46500
+ indexes.set(slot, new Map(block.signatures.map((signature, index) => [signature, index])));
46501
+ if (events2.some((event) => event.transaction.slot === slot && !indexes.get(slot).has(event.transaction.signature)))
46502
+ throw new Error("Historical transaction is missing from its canonical block");
46503
+ }
46504
+ events2.sort((a, b) => a.transaction.slot - b.transaction.slot || (indexes.get(a.transaction.slot)?.get(a.transaction.signature) ?? 0) - (indexes.get(b.transaction.slot)?.get(b.transaction.signature) ?? 0));
46505
+ let state = {
46506
+ position: 0n,
46507
+ entryPriceE8: 0n,
46508
+ fundingCheckpoint: 0n,
46509
+ collateral: 0n
46510
+ };
46511
+ for (const event of events2) {
46512
+ if ("transfer" in event) {
46513
+ state = replayMargin(state, BigInt(event.transfer.amount.toString()), event.transfer.toMarket);
46514
+ continue;
46515
+ }
46516
+ if ("liquidation" in event.order.kind) {
46517
+ if (!event.order.trader.equals(this.owner))
46518
+ throw new Error("Historical backstop exposure requires an authorized historical position view");
46519
+ state = {
46520
+ position: 0n,
46521
+ entryPriceE8: 0n,
46522
+ fundingCheckpoint: BigInt(event.order.fundingIndex.toString())
46523
+ };
46524
+ continue;
46525
+ }
46526
+ const fill = await this.fill(event.id);
46527
+ const result = replayFill(state, fill, BigInt(event.order.fundingIndex.toString()), event.order.maker.equals(this.owner));
46528
+ state = result.state;
46529
+ if (event.id.equals(target))
46530
+ return { id: target, fill, pnl: result.pnl, transaction: targetTx };
46531
+ }
46532
+ throw new Error("Historical execution could not be reconciled");
46533
+ }
46534
+ async settlement(id) {
46535
+ const key = id.toBase58();
46536
+ const cached = this.transactions.get(key);
46537
+ if (cached)
46538
+ return { ...cached, orderId: id };
46539
+ const result = await settlementTransaction(this.connection, this.program, id, { orderId: id });
46540
+ this.transactions.set(key, result);
46541
+ return result;
46542
+ }
46543
+ async scan(name2, offset2) {
46544
+ const accounts2 = await this.connection.getProgramAccounts(this.program.programId, {
46545
+ commitment: "confirmed",
46546
+ filters: [
46547
+ { memcmp: this.program.coder.accounts.memcmp(name2) },
46548
+ { memcmp: { offset: offset2, bytes: this.owner.toBase58() } }
46549
+ ]
46550
+ });
46551
+ if (accounts2.some((item) => !item.account.owner.equals(this.program.programId)))
46552
+ throw new Error("History account owner is invalid");
46553
+ return accounts2;
46554
+ }
46555
+ }
46556
+
46069
46557
  // src/trade/amount.ts
46070
46558
  function resolveAmount(selector, available, name2) {
46071
46559
  u64(available, "available");
@@ -46119,7 +46607,7 @@ function tradeLimit(input, direction, oraclePriceE8) {
46119
46607
  }
46120
46608
 
46121
46609
  // src/trade/flow.ts
46122
- import { transferAddress as transferAddress3 } from "@depthhq/bindings";
46610
+ import { transferAddress as transferAddress4 } from "@depthhq/bindings";
46123
46611
 
46124
46612
  class TradeFlow {
46125
46613
  client;
@@ -46133,7 +46621,7 @@ class TradeFlow {
46133
46621
  throw new RangeError("clientNonce must be an unsigned 64-bit bigint");
46134
46622
  }
46135
46623
  this.id = client.trade.operation(nonce).id;
46136
- this.allocationId = transferAddress3(client.options.wallet.publicKey, nonce, client.program.programId);
46624
+ this.allocationId = transferAddress4(client.options.wallet.publicKey, nonce, client.program.programId);
46137
46625
  }
46138
46626
  async status() {
46139
46627
  const [order, allocation] = await this.client.options.connection.getMultipleAccountsInfo([this.id, this.allocationId], "confirmed");
@@ -46329,10 +46817,10 @@ class DepthView {
46329
46817
 
46330
46818
  // src/client/client.ts
46331
46819
  function pda(seeds, programId = DEPTH_PROGRAM_ID7) {
46332
- return PublicKey8.findProgramAddressSync(seeds, programId)[0];
46820
+ return PublicKey9.findProgramAddressSync(seeds, programId)[0];
46333
46821
  }
46334
46822
  function nonce() {
46335
- return new anchor6.BN(randomBytes3(8), "le");
46823
+ return new anchor8.BN(randomBytes3(8), "le");
46336
46824
  }
46337
46825
  function enumName2(value2) {
46338
46826
  return Object.keys(value2)[0] ?? "unknown";
@@ -46343,7 +46831,7 @@ class DepthClient {
46343
46831
  program;
46344
46832
  provider;
46345
46833
  position;
46346
- marketAddress = marketAddress6();
46834
+ marketAddress = marketAddress7();
46347
46835
  protocolAddress = protocolAddress4();
46348
46836
  mxeAddress = getMXEAccAddress(DEPTH_PROGRAM_ID7);
46349
46837
  get catalog() {
@@ -46358,17 +46846,21 @@ class DepthClient {
46358
46846
  get recovery() {
46359
46847
  return new DepthRecovery(this.program, this.options.connection, this.options.wallet.publicKey);
46360
46848
  }
46849
+ historyClient;
46850
+ get history() {
46851
+ return this.historyClient ??= new ExecutionHistory(this.program, this.options.connection, this.options.wallet.publicKey, (id) => this.requestFillView(id));
46852
+ }
46361
46853
  constructor(options) {
46362
46854
  this.options = options;
46363
46855
  this.provider = new DepthProvider(options.connection, options.wallet, {
46364
46856
  commitment: "confirmed",
46365
46857
  preflightCommitment: "confirmed"
46366
46858
  });
46367
- this.program = new anchor6.Program(DEPTH_IDL3, this.provider);
46859
+ this.program = new anchor8.Program(DEPTH_IDL3, this.provider);
46368
46860
  this.position = this.positionActions();
46369
46861
  }
46370
46862
  static async create(options) {
46371
- const appId = typeof options.appId === "string" ? new PublicKey8(options.appId) : options.appId;
46863
+ const appId = typeof options.appId === "string" ? new PublicKey9(options.appId) : options.appId;
46372
46864
  const resolved = {
46373
46865
  ...options,
46374
46866
  ...await resolveConnection(options),
@@ -46472,7 +46964,7 @@ class DepthClient {
46472
46964
  }
46473
46965
  async requestFillView(order) {
46474
46966
  const record = await this.read("OrderRecord", order);
46475
- if (!record.trader.equals(this.options.wallet.publicKey) || !record.market.equals(this.marketAddress) || enumName2(record.kind) !== "trade" || enumName2(record.status) !== "filled")
46967
+ if (!record.trader.equals(this.options.wallet.publicKey) && !record.maker?.equals(this.options.wallet.publicKey) || !record.market.equals(this.marketAddress) || enumName2(record.kind) !== "trade" || enumName2(record.status) !== "filled")
46476
46968
  throw new Error("Filled trade does not belong to this wallet and market");
46477
46969
  const viewNonce = nonce();
46478
46970
  const view = pda([
@@ -46586,7 +47078,7 @@ class DepthClient {
46586
47078
  return this.funding.release(amount, clientNonce ?? BigInt(nonce().toString()));
46587
47079
  }
46588
47080
  async depositRequest(sourceOrAmount, amount, clientNonce) {
46589
- if (sourceOrAmount instanceof PublicKey8) {
47081
+ if (sourceOrAmount instanceof PublicKey9) {
46590
47082
  if (amount === undefined || clientNonce === undefined)
46591
47083
  throw new RangeError("Source deposits require amount and client nonce");
46592
47084
  return this.funding.deposit(sourceOrAmount, amount, clientNonce);
@@ -46597,7 +47089,7 @@ class DepthClient {
46597
47089
  return this.funding.deposit(source, sourceOrAmount, amount ?? BigInt(nonce().toString()));
46598
47090
  }
46599
47091
  async withdrawRequest(destinationOrAmount, amount, clientNonce) {
46600
- if (destinationOrAmount instanceof PublicKey8) {
47092
+ if (destinationOrAmount instanceof PublicKey9) {
46601
47093
  if (amount === undefined || clientNonce === undefined)
46602
47094
  throw new RangeError("Destination withdrawals require amount and client nonce");
46603
47095
  return this.funding.withdraw(destinationOrAmount, amount, clientNonce);
@@ -46612,6 +47104,9 @@ class DepthClient {
46612
47104
  }
46613
47105
  accountActions() {
46614
47106
  const actions = {
47107
+ state: () => balanceState(this.program, this.options.connection, this.options.wallet.publicKey, this.funding.balance),
47108
+ detail: (item) => new FundingDiscovery(this.program, this.options.connection, this.options.wallet.publicKey).detail(item),
47109
+ transaction: (item) => new FundingDiscovery(this.program, this.options.connection, this.options.wallet.publicKey).transaction(item),
46615
47110
  history: (options) => new FundingDiscovery(this.program, this.options.connection, this.options.wallet.publicKey).history(options),
46616
47111
  pending: (options) => new FundingDiscovery(this.program, this.options.connection, this.options.wallet.publicKey).pending(options),
46617
47112
  cancelOpen: () => this.funding.cancelOpenBalance(),
@@ -46626,6 +47121,9 @@ class DepthClient {
46626
47121
  summary: async (options = {
46627
47122
  timeoutMs: 180000
46628
47123
  }) => {
47124
+ const state = await actions.state();
47125
+ if (state.status === "uninitialized")
47126
+ return { ...state, status: "uninitialized", amount: 0n };
46629
47127
  const view = await this.requestBalanceView();
46630
47128
  const result = await view.wait(options);
46631
47129
  if (result.status !== "pending")
@@ -46646,6 +47144,23 @@ class DepthClient {
46646
47144
  addMargin: (amount, clientNonce) => typeof amount === "bigint" && clientNonce !== undefined ? this.funding.allocate(amount, clientNonce) : this.allocateRequest({ marketId: SOL_USD_MARKET_ID3, amount }, clientNonce),
46647
47145
  removeMargin: (amount, clientNonce) => typeof amount === "bigint" && clientNonce !== undefined ? this.funding.release(amount, clientNonce) : this.releaseRequest({ marketId: SOL_USD_MARKET_ID3, amount }, clientNonce),
46648
47146
  open: async () => this.funding.openMarket(),
47147
+ transaction: () => settlementTransaction(this.options.connection, this.program, address2, {
47148
+ trader: this.options.wallet.publicKey,
47149
+ market: this.marketAddress
47150
+ }),
47151
+ pnl: async () => {
47152
+ const position = await this.positionActions(id).summary();
47153
+ const [market, account] = await Promise.all([
47154
+ this.market(),
47155
+ this.read("MarketAccount", address2)
47156
+ ]);
47157
+ const age = Math.floor(Date.now() / 1000) - market.state.oracleTimestamp.toNumber();
47158
+ if (age < 0 || age > market.state.config.maxOracleAgeSeconds)
47159
+ throw new Error("A fresh oracle price is required to value this position");
47160
+ if (position.version !== BigInt(account.version.toString()) || enumName2(account.status) !== "ready")
47161
+ throw new Error("The position changed during valuation; refresh its private view");
47162
+ return positionPnl(position, BigInt(market.state.oraclePriceE8.toString()), BigInt(market.state.fundingIndex.toString()));
47163
+ },
46649
47164
  summary: async (options = {
46650
47165
  timeoutMs: 180000
46651
47166
  }) => {
@@ -46700,7 +47215,12 @@ class DepthClient {
46700
47215
  reduce: (input) => this.submitTrade(input, "reduce"),
46701
47216
  close: (input) => this.submitTrade(input, "close"),
46702
47217
  reverse: (input) => this.submitTrade(input, "reverse"),
46703
- operation: (clientNonce) => new DepthOperation(this.orderAddress(clientNonce), undefined, this.program, this.options.connection, (order) => this.requestFillView(order)),
47218
+ operation: (clientNonce) => new DepthOperation(this.orderAddress(clientNonce), undefined, this.program, this.options.connection, (order) => this.requestFillView(order), undefined, async () => {
47219
+ const detail = await this.history.execution(clientNonce);
47220
+ if (!detail.pnl)
47221
+ throw new Error("This execution does not close any exposure");
47222
+ return detail.pnl;
47223
+ }),
46704
47224
  flow: (clientNonce) => new TradeFlow(this, clientNonce),
46705
47225
  unpairedAllocations: (options) => new FundingDiscovery(this.program, this.options.connection, this.options.wallet.publicKey).unpairedAllocations(options)
46706
47226
  };
@@ -46852,7 +47372,7 @@ class DepthClient {
46852
47372
  }), inputNonce);
46853
47373
  const offset2 = nonce();
46854
47374
  const queue = await this.queue("match_order", offset2);
46855
- const signature = await this.program.methods.submitOrder(offset2, orderNonce, appId, app.feeBps, app.version, new anchor6.BN(deadline), market.state.revision, market.state.oracleTimestamp, ciphertexts, Array.from(inputKey), new anchor6.BN(inputNonce, "le")).accountsPartial({
47375
+ const signature = await this.program.methods.submitOrder(offset2, orderNonce, appId, app.feeBps, app.version, new anchor8.BN(deadline), market.state.revision, market.state.oracleTimestamp, ciphertexts, Array.from(inputKey), new anchor8.BN(inputNonce, "le")).accountsPartial({
46856
47376
  ...queue,
46857
47377
  trader: this.options.wallet.publicKey,
46858
47378
  protocol: this.protocolAddress,
@@ -46873,7 +47393,7 @@ class DepthClient {
46873
47393
  isWritable: true
46874
47394
  }
46875
47395
  ]).rpc({ commitment: "confirmed" }).catch((error) => submissionError(order.toBase58(), error));
46876
- return new DepthOperation(order, signature, this.program, this.options.connection, (id) => this.requestFillView(id));
47396
+ return new DepthOperation(order, signature, this.program, this.options.connection, (id) => this.requestFillView(id), position);
46877
47397
  }
46878
47398
  validateTrade(market, protocol, account, app, appId, intent = "increase", deadline) {
46879
47399
  const now = Math.floor(Date.now() / 1000);
@@ -47043,6 +47563,8 @@ export {
47043
47563
  verifyDeployment,
47044
47564
  resolveConnection,
47045
47565
  resolveAmount,
47566
+ prepare_depth,
47567
+ positionPnl,
47046
47568
  manifestBytes,
47047
47569
  create_depth_data,
47048
47570
  createDepth as create_depth,
@@ -47056,6 +47578,7 @@ export {
47056
47578
  MarketCatalog,
47057
47579
  FundingDiscovery,
47058
47580
  FundingClient,
47581
+ ExecutionHistory,
47059
47582
  DepthView,
47060
47583
  DepthRecovery,
47061
47584
  DepthProvider,
@@ -1,17 +1,24 @@
1
1
  import * as anchor from "@anchor-lang/core";
2
2
  import type { OperationSnapshot } from "@depthhq/schema";
3
3
  import { Connection, PublicKey } from "@solana/web3.js";
4
- import type { DepthView, FillSnapshot } from "../view/view.js";
4
+ import type { DepthView, FillSnapshot, PositionSnapshot } from "../view/view.js";
5
+ import { type PositionPnl } from "../position/pnl.js";
6
+ import { type SettlementTransaction } from "../chain/settlement.js";
5
7
  export declare class DepthOperation {
6
8
  readonly id: PublicKey;
7
9
  readonly signature: string | undefined;
8
10
  private readonly program;
9
11
  private readonly connection;
10
12
  private readonly requestFillView?;
13
+ private readonly priorPosition?;
14
+ private readonly historicalPnl?;
11
15
  private viewPromise?;
12
16
  private view?;
13
17
  private fill?;
14
- constructor(id: PublicKey, signature: string | undefined, program: anchor.Program, connection: Connection, requestFillView?: ((order: PublicKey) => Promise<DepthView>) | undefined);
18
+ private settlement?;
19
+ constructor(id: PublicKey, signature: string | undefined, program: anchor.Program, connection: Connection, requestFillView?: ((order: PublicKey) => Promise<DepthView>) | undefined, priorPosition?: PositionSnapshot | undefined, historicalPnl?: (() => Promise<PositionPnl>) | undefined);
20
+ transaction(): Promise<SettlementTransaction>;
21
+ pnl(): Promise<PositionPnl>;
15
22
  private readOrder;
16
23
  status(): Promise<OperationSnapshot>;
17
24
  cancel(): Promise<OperationSnapshot>;
@@ -0,0 +1,14 @@
1
+ import type { FillSnapshot, PositionSnapshot } from "../view/view.js";
2
+ export type PositionPnl = {
3
+ side: "long" | "short";
4
+ state: "open" | "closed" | "reduced" | "reversed";
5
+ entryPriceE8: bigint;
6
+ priceE8: bigint;
7
+ collateral: bigint | null;
8
+ gross: bigint;
9
+ funding: bigint;
10
+ fee: bigint;
11
+ net: bigint;
12
+ returnBps: bigint | null;
13
+ };
14
+ export declare function positionPnl(position: PositionSnapshot, priceE8: bigint, fundingIndex: bigint, fill?: FillSnapshot): PositionPnl;
@@ -1,7 +1,7 @@
1
1
  import * as anchor from "@anchor-lang/core";
2
2
  import { Connection, PublicKey } from "@solana/web3.js";
3
3
  export type BalanceSnapshot = {
4
- status: "pending" | "ready" | "stale";
4
+ status: "uninitialized" | "pending" | "ready" | "stale";
5
5
  id: string;
6
6
  version: bigint;
7
7
  slot: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@depthhq/sdk",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -39,13 +39,13 @@
39
39
  "dependencies": {
40
40
  "@anchor-lang/core": "1.0.2",
41
41
  "@arcium-hq/client": "0.13.2",
42
- "@depthhq/bindings": "0.1.0",
43
- "@depthhq/schema": "0.1.0",
44
42
  "@noble/ciphers": "1.3.0",
45
43
  "@noble/ed25519": "1.7.5",
46
44
  "@noble/hashes": "1.8.0",
47
45
  "@solana/web3.js": "1.99.0",
48
- "buffer": "6.0.3"
46
+ "buffer": "6.0.3",
47
+ "@depthhq/bindings": "0.1.1",
48
+ "@depthhq/schema": "0.1.1"
49
49
  },
50
50
  "scripts": {
51
51
  "build": "node ../../scripts/build-package.mjs sdk",