@depthhq/sdk 0.1.0 → 0.1.1
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/account/discovery.d.ts +6 -0
- package/dist/chain/settlement.d.ts +15 -0
- package/dist/chain/transaction.d.ts +12 -0
- package/dist/client/client.d.ts +7 -0
- package/dist/client/types.d.ts +3 -0
- package/dist/history/history.d.ts +26 -0
- package/dist/history/replay.d.ts +13 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +487 -22
- package/dist/operation/operation.d.ts +9 -2
- package/dist/position/pnl.d.ts +14 -0
- package/package.json +4 -4
|
@@ -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,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>;
|
package/dist/client/client.d.ts
CHANGED
|
@@ -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,8 @@ export declare class DepthClient {
|
|
|
48
51
|
private withdrawRequest;
|
|
49
52
|
private accountActions;
|
|
50
53
|
readonly account: (() => {
|
|
54
|
+
detail: (item: Parameters<FundingDiscovery["detail"]>[0]) => Promise<import("../account/discovery.js").ReceiptDetail>;
|
|
55
|
+
transaction: (item: Parameters<FundingDiscovery["transaction"]>[0]) => Promise<import("../account/discovery.js").ReceiptDetail>;
|
|
51
56
|
history: (options?: Parameters<FundingDiscovery["history"]>[0]) => Promise<import("../account/discovery.js").PendingPage>;
|
|
52
57
|
pending: (options?: Parameters<FundingDiscovery["pending"]>[0]) => Promise<import("../account/discovery.js").PendingPage>;
|
|
53
58
|
cancelOpen: () => Promise<string>;
|
|
@@ -73,6 +78,8 @@ export declare class DepthClient {
|
|
|
73
78
|
pollMs?: number;
|
|
74
79
|
}) => Promise<BalanceSnapshot>;
|
|
75
80
|
}) & {
|
|
81
|
+
detail: (item: Parameters<FundingDiscovery["detail"]>[0]) => Promise<import("../account/discovery.js").ReceiptDetail>;
|
|
82
|
+
transaction: (item: Parameters<FundingDiscovery["transaction"]>[0]) => Promise<import("../account/discovery.js").ReceiptDetail>;
|
|
76
83
|
history: (options?: Parameters<FundingDiscovery["history"]>[0]) => Promise<import("../account/discovery.js").PendingPage>;
|
|
77
84
|
pending: (options?: Parameters<FundingDiscovery["pending"]>[0]) => Promise<import("../account/discovery.js").PendingPage>;
|
|
78
85
|
cancelOpen: () => Promise<string>;
|
package/dist/client/types.d.ts
CHANGED
|
@@ -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";
|
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
|
|
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
|
|
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
|
|
43631
|
+
import { PublicKey as PublicKey9 } from "@solana/web3.js";
|
|
43632
43632
|
|
|
43633
43633
|
// src/chain/random.ts
|
|
43634
43634
|
function randomBytes3(length) {
|
|
@@ -44625,7 +44625,7 @@ async function upgradeAuthority(connection) {
|
|
|
44625
44625
|
if (!program?.executable || !program.owner.equals(loader) || program.data.length !== 36 || program.data.readUInt32LE(0) !== 2) {
|
|
44626
44626
|
throw unavailable("Depth program is not deployed as an upgradeable program");
|
|
44627
44627
|
}
|
|
44628
|
-
const data = await connection.getAccountInfo(new PublicKey3(program.data.subarray(4)), "confirmed");
|
|
44628
|
+
const data = await connection.getAccountInfo(new PublicKey3(program.data.subarray(4)), { commitment: "confirmed", dataSlice: { offset: 0, length: 45 } });
|
|
44629
44629
|
if (!data?.owner.equals(loader) || data.data.length < 45 || data.data.readUInt32LE(0) !== 3 || data.data[12] !== 1) {
|
|
44630
44630
|
throw unavailable("Depth deployment has no verifiable upgrade authority");
|
|
44631
44631
|
}
|
|
@@ -44999,6 +44999,124 @@ import {
|
|
|
44999
44999
|
withdrawalAddress
|
|
45000
45000
|
} from "@depthhq/bindings";
|
|
45001
45001
|
import { PublicKey as PublicKey4 } from "@solana/web3.js";
|
|
45002
|
+
|
|
45003
|
+
// src/chain/transaction.ts
|
|
45004
|
+
init_buffer();
|
|
45005
|
+
import * as anchor4 from "@anchor-lang/core";
|
|
45006
|
+
function depthInstructions(transaction, program) {
|
|
45007
|
+
if (!transaction.meta || transaction.meta.err)
|
|
45008
|
+
return [];
|
|
45009
|
+
const keys = transaction.transaction.message.getAccountKeys({
|
|
45010
|
+
accountKeysFromLookups: transaction.meta.loadedAddresses
|
|
45011
|
+
});
|
|
45012
|
+
const instructions2 = [
|
|
45013
|
+
...transaction.transaction.message.compiledInstructions.map((ix) => ({
|
|
45014
|
+
programIdIndex: ix.programIdIndex,
|
|
45015
|
+
accounts: ix.accountKeyIndexes,
|
|
45016
|
+
data: Buffer2.from(ix.data)
|
|
45017
|
+
})),
|
|
45018
|
+
...(transaction.meta.innerInstructions ?? []).flatMap((group) => group.instructions.map((ix) => ({
|
|
45019
|
+
programIdIndex: ix.programIdIndex,
|
|
45020
|
+
accounts: ix.accounts,
|
|
45021
|
+
data: Buffer2.from(anchor4.utils.bytes.bs58.decode(ix.data))
|
|
45022
|
+
})))
|
|
45023
|
+
];
|
|
45024
|
+
return instructions2.flatMap((ix) => {
|
|
45025
|
+
if (!keys.get(ix.programIdIndex)?.equals(program.programId))
|
|
45026
|
+
return [];
|
|
45027
|
+
let definition = program.idl.instructions.find((item) => ix.data.subarray(0, 8).equals(Buffer2.from(item.discriminator)));
|
|
45028
|
+
if (!definition && ix.data.subarray(0, 8).equals(Buffer2.from("057da1a57b4b7ec6", "hex"))) {
|
|
45029
|
+
const current = program.idl.instructions.find((item) => item.name === "debitMarketV2Callback");
|
|
45030
|
+
if (current)
|
|
45031
|
+
definition = { ...current, name: "debitMarketCallback" };
|
|
45032
|
+
}
|
|
45033
|
+
return definition ? [{ definition, accounts: ix.accounts.map((index) => keys.get(index)) }] : [];
|
|
45034
|
+
});
|
|
45035
|
+
}
|
|
45036
|
+
async function receiptTransaction(connection, program, address2, names) {
|
|
45037
|
+
let before;
|
|
45038
|
+
for (let page = 0;page < 10; page++) {
|
|
45039
|
+
const signatures = await connection.getSignaturesForAddress(address2, { before, limit: 50 }, "confirmed");
|
|
45040
|
+
for (const signature of signatures) {
|
|
45041
|
+
if (signature.err)
|
|
45042
|
+
continue;
|
|
45043
|
+
const transaction = await connection.getTransaction(signature.signature, {
|
|
45044
|
+
commitment: "confirmed",
|
|
45045
|
+
maxSupportedTransactionVersion: 0
|
|
45046
|
+
});
|
|
45047
|
+
if (!transaction)
|
|
45048
|
+
throw new Error("Transaction history is unavailable; retry with an archival RPC");
|
|
45049
|
+
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)));
|
|
45050
|
+
if (changed)
|
|
45051
|
+
return {
|
|
45052
|
+
signature: signature.signature,
|
|
45053
|
+
slot: signature.slot,
|
|
45054
|
+
...transaction.blockTime == null ? {} : { timestamp: transaction.blockTime }
|
|
45055
|
+
};
|
|
45056
|
+
}
|
|
45057
|
+
if (signatures.length < 50)
|
|
45058
|
+
break;
|
|
45059
|
+
before = signatures.at(-1).signature;
|
|
45060
|
+
}
|
|
45061
|
+
throw new Error(`Receipt transaction for ${address2.toBase58()} was not found in recent history`);
|
|
45062
|
+
}
|
|
45063
|
+
|
|
45064
|
+
// src/chain/settlement.ts
|
|
45065
|
+
function settlementOrder(transaction, program) {
|
|
45066
|
+
const instruction = depthInstructions(transaction, program).find((ix) => ix.definition.name === "sealClearingCallback");
|
|
45067
|
+
if (!instruction)
|
|
45068
|
+
return;
|
|
45069
|
+
const orderIndex = instruction.definition.accounts.findIndex((account) => account.name === "order");
|
|
45070
|
+
if (orderIndex < 0)
|
|
45071
|
+
throw new Error("Settlement callback has no order account");
|
|
45072
|
+
return instruction.accounts[orderIndex];
|
|
45073
|
+
}
|
|
45074
|
+
async function settlementTransaction(connection, program, address2, match) {
|
|
45075
|
+
let before;
|
|
45076
|
+
for (let page = 0;page < 10; page++) {
|
|
45077
|
+
const signatures = await connection.getSignaturesForAddress(address2, { before, limit: 50 }, "confirmed");
|
|
45078
|
+
for (const signature of signatures) {
|
|
45079
|
+
if (signature.err)
|
|
45080
|
+
continue;
|
|
45081
|
+
const transaction = await connection.getTransaction(signature.signature, {
|
|
45082
|
+
commitment: "confirmed",
|
|
45083
|
+
maxSupportedTransactionVersion: 0
|
|
45084
|
+
});
|
|
45085
|
+
if (!transaction)
|
|
45086
|
+
throw new Error("Transaction history is unavailable; retry with an archival RPC");
|
|
45087
|
+
const orderId = settlementOrder(transaction, program);
|
|
45088
|
+
if (!orderId)
|
|
45089
|
+
continue;
|
|
45090
|
+
if ("orderId" in match) {
|
|
45091
|
+
if (orderId.equals(match.orderId))
|
|
45092
|
+
return {
|
|
45093
|
+
signature: signature.signature,
|
|
45094
|
+
slot: signature.slot,
|
|
45095
|
+
orderId,
|
|
45096
|
+
...transaction.blockTime == null ? {} : { timestamp: transaction.blockTime }
|
|
45097
|
+
};
|
|
45098
|
+
} else {
|
|
45099
|
+
const info = await connection.getAccountInfo(orderId, "confirmed");
|
|
45100
|
+
if (!info?.owner.equals(program.programId))
|
|
45101
|
+
throw new Error("Settlement receipt is unavailable");
|
|
45102
|
+
const order = program.coder.accounts.decode("orderRecord", info.data);
|
|
45103
|
+
if (order.trader.equals(match.trader) && order.market.equals(match.market) && "trade" in order.kind && "filled" in order.status)
|
|
45104
|
+
return {
|
|
45105
|
+
signature: signature.signature,
|
|
45106
|
+
slot: signature.slot,
|
|
45107
|
+
orderId,
|
|
45108
|
+
...transaction.blockTime == null ? {} : { timestamp: transaction.blockTime }
|
|
45109
|
+
};
|
|
45110
|
+
}
|
|
45111
|
+
}
|
|
45112
|
+
if (signatures.length < 50)
|
|
45113
|
+
break;
|
|
45114
|
+
before = signatures.at(-1).signature;
|
|
45115
|
+
}
|
|
45116
|
+
throw new Error("Settlement transaction was not found in recent history");
|
|
45117
|
+
}
|
|
45118
|
+
|
|
45119
|
+
// src/account/discovery.ts
|
|
45002
45120
|
function status(state) {
|
|
45003
45121
|
return Object.keys(state.status)[0] ?? "unknown";
|
|
45004
45122
|
}
|
|
@@ -45012,6 +45130,28 @@ class FundingDiscovery {
|
|
|
45012
45130
|
this.connection = connection;
|
|
45013
45131
|
this.owner = owner;
|
|
45014
45132
|
}
|
|
45133
|
+
async transaction(item) {
|
|
45134
|
+
return this.detail(item);
|
|
45135
|
+
}
|
|
45136
|
+
async detail(item) {
|
|
45137
|
+
const name2 = item.kind === "deposit" ? "depositReceipt" : item.kind === "withdrawal" ? "withdrawalReceipt" : item.kind === "allocation" || item.kind === "release" ? "marginTransfer" : "orderRecord";
|
|
45138
|
+
const info = await this.connection.getAccountInfo(item.id, "confirmed");
|
|
45139
|
+
if (!info?.owner.equals(this.program.programId))
|
|
45140
|
+
throw new Error("Receipt is unavailable");
|
|
45141
|
+
const state = this.program.coder.accounts.decode(name2, info.data);
|
|
45142
|
+
const canonical = this.project(name2, item.id, state, true);
|
|
45143
|
+
if (!canonical || canonical.kind !== item.kind || canonical.nonce !== item.nonce)
|
|
45144
|
+
throw new Error("Receipt does not match this wallet and operation");
|
|
45145
|
+
if ((canonical.kind === "trade" || canonical.kind === "risk") && canonical.status === "filled")
|
|
45146
|
+
return settlementTransaction(this.connection, this.program, item.id, {
|
|
45147
|
+
orderId: item.id
|
|
45148
|
+
});
|
|
45149
|
+
const transaction = await receiptTransaction(this.connection, this.program, item.id);
|
|
45150
|
+
return {
|
|
45151
|
+
...transaction,
|
|
45152
|
+
...state.amount === undefined ? {} : { amount: BigInt(state.amount.toString()) }
|
|
45153
|
+
};
|
|
45154
|
+
}
|
|
45015
45155
|
async unpairedAllocations(options = {}) {
|
|
45016
45156
|
const limit = options.limit ?? 20;
|
|
45017
45157
|
if (!Number.isSafeInteger(limit) || limit < 1 || limit > 100)
|
|
@@ -45216,7 +45356,7 @@ class FundingDiscovery {
|
|
|
45216
45356
|
}
|
|
45217
45357
|
|
|
45218
45358
|
// src/account/funding.ts
|
|
45219
|
-
import * as
|
|
45359
|
+
import * as anchor6 from "@anchor-lang/core";
|
|
45220
45360
|
import {
|
|
45221
45361
|
balanceAddress,
|
|
45222
45362
|
depositAddress as depositAddress2,
|
|
@@ -45246,7 +45386,7 @@ async function confirmReceipt(id, status2, advance, options = {}) {
|
|
|
45246
45386
|
}
|
|
45247
45387
|
|
|
45248
45388
|
// src/trade/input.ts
|
|
45249
|
-
import * as
|
|
45389
|
+
import * as anchor5 from "@anchor-lang/core";
|
|
45250
45390
|
function encodeSide(direction) {
|
|
45251
45391
|
if (direction !== "long" && direction !== "short")
|
|
45252
45392
|
throw new RangeError("Direction must be long or short");
|
|
@@ -45256,12 +45396,12 @@ function u64(value2, name2) {
|
|
|
45256
45396
|
if (typeof value2 !== "bigint" || value2 < 0n || value2 > (1n << 64n) - 1n) {
|
|
45257
45397
|
throw new RangeError(`${name2} must be an unsigned 64-bit bigint`);
|
|
45258
45398
|
}
|
|
45259
|
-
return new
|
|
45399
|
+
return new anchor5.BN(value2.toString());
|
|
45260
45400
|
}
|
|
45261
45401
|
|
|
45262
45402
|
// src/account/funding.ts
|
|
45263
45403
|
function offset() {
|
|
45264
|
-
return new
|
|
45404
|
+
return new anchor6.BN(randomBytes3(8), "le");
|
|
45265
45405
|
}
|
|
45266
45406
|
function status2(value2) {
|
|
45267
45407
|
return Object.keys(value2)[0] ?? "unknown";
|
|
@@ -45770,6 +45910,42 @@ import {
|
|
|
45770
45910
|
SOL_USD_MARKET_ID as SOL_USD_MARKET_ID2
|
|
45771
45911
|
} from "@depthhq/bindings";
|
|
45772
45912
|
import { PublicKey as PublicKey6 } from "@solana/web3.js";
|
|
45913
|
+
|
|
45914
|
+
// src/position/pnl.ts
|
|
45915
|
+
var scale = 100000000000n;
|
|
45916
|
+
function positionPnl(position, priceE8, fundingIndex, fill) {
|
|
45917
|
+
if (position.status !== "ready" || position.position === undefined || position.position === 0n || position.entryPriceE8 === undefined || position.fundingCheckpoint === undefined || position.collateral !== undefined && position.collateral < 0n || priceE8 <= 0n)
|
|
45918
|
+
throw new Error("A ready open position and a positive price are required");
|
|
45919
|
+
const size = position.position < 0n ? -position.position : position.position;
|
|
45920
|
+
const sign = position.position > 0n ? 1n : -1n;
|
|
45921
|
+
let closing = size;
|
|
45922
|
+
let fee = 0n;
|
|
45923
|
+
let state = "open";
|
|
45924
|
+
if (fill) {
|
|
45925
|
+
if (fill.status !== "ready" || fill.side !== -sign || fill.size === undefined || fill.size <= 0n || fill.executionPriceE8 !== priceE8 || fill.fee === undefined || fill.fee < 0n)
|
|
45926
|
+
throw new Error("A ready opposite-side execution is required");
|
|
45927
|
+
closing = fill.size < size ? fill.size : size;
|
|
45928
|
+
fee = fill.fee;
|
|
45929
|
+
state = fill.size === size ? "closed" : fill.size < size ? "reduced" : "reversed";
|
|
45930
|
+
}
|
|
45931
|
+
const gross = sign * closing * (priceE8 - position.entryPriceE8) / scale;
|
|
45932
|
+
const funding = position.position * (fundingIndex - position.fundingCheckpoint) / scale;
|
|
45933
|
+
const net = gross - funding - fee;
|
|
45934
|
+
return {
|
|
45935
|
+
side: sign > 0n ? "long" : "short",
|
|
45936
|
+
state,
|
|
45937
|
+
entryPriceE8: position.entryPriceE8,
|
|
45938
|
+
priceE8,
|
|
45939
|
+
collateral: position.collateral ?? null,
|
|
45940
|
+
gross,
|
|
45941
|
+
funding,
|
|
45942
|
+
fee,
|
|
45943
|
+
net,
|
|
45944
|
+
returnBps: position.collateral !== undefined && position.collateral > 0n ? net * 10000n / position.collateral : null
|
|
45945
|
+
};
|
|
45946
|
+
}
|
|
45947
|
+
|
|
45948
|
+
// src/operation/operation.ts
|
|
45773
45949
|
function enumName(value2) {
|
|
45774
45950
|
return Object.keys(value2)[0] ?? "unknown";
|
|
45775
45951
|
}
|
|
@@ -45780,15 +45956,40 @@ class DepthOperation {
|
|
|
45780
45956
|
program;
|
|
45781
45957
|
connection;
|
|
45782
45958
|
requestFillView;
|
|
45959
|
+
priorPosition;
|
|
45960
|
+
historicalPnl;
|
|
45783
45961
|
viewPromise;
|
|
45784
45962
|
view;
|
|
45785
45963
|
fill;
|
|
45786
|
-
|
|
45964
|
+
settlement;
|
|
45965
|
+
constructor(id, signature, program, connection, requestFillView, priorPosition, historicalPnl) {
|
|
45787
45966
|
this.id = id;
|
|
45788
45967
|
this.signature = signature;
|
|
45789
45968
|
this.program = program;
|
|
45790
45969
|
this.connection = connection;
|
|
45791
45970
|
this.requestFillView = requestFillView;
|
|
45971
|
+
this.priorPosition = priorPosition;
|
|
45972
|
+
this.historicalPnl = historicalPnl;
|
|
45973
|
+
}
|
|
45974
|
+
async transaction() {
|
|
45975
|
+
if (this.settlement)
|
|
45976
|
+
return this.settlement;
|
|
45977
|
+
const snapshot = await this.status();
|
|
45978
|
+
if (snapshot.status !== "finalized" || snapshot.outcome !== "filled")
|
|
45979
|
+
throw new Error("Confirm the trade before reading its settlement transaction");
|
|
45980
|
+
this.settlement = await settlementTransaction(this.connection, this.program, this.id, { orderId: this.id });
|
|
45981
|
+
return this.settlement;
|
|
45982
|
+
}
|
|
45983
|
+
async pnl() {
|
|
45984
|
+
if (!this.priorPosition && this.historicalPnl)
|
|
45985
|
+
return this.historicalPnl();
|
|
45986
|
+
const { order } = await this.readOrder();
|
|
45987
|
+
if (!this.priorPosition || this.priorPosition.version !== BigInt(order.traderVersion.toString()))
|
|
45988
|
+
throw new Error("The private position before this execution is unavailable");
|
|
45989
|
+
const fill = await this.privateResult();
|
|
45990
|
+
if (fill.executionPriceE8 === undefined)
|
|
45991
|
+
throw new Error("Execution price is unavailable");
|
|
45992
|
+
return positionPnl(this.priorPosition, fill.executionPriceE8, BigInt(order.fundingIndex.toString()), fill);
|
|
45792
45993
|
}
|
|
45793
45994
|
async readOrder() {
|
|
45794
45995
|
const response = await this.connection.getAccountInfoAndContext(this.id, "confirmed");
|
|
@@ -46066,6 +46267,240 @@ class DepthRecovery {
|
|
|
46066
46267
|
}
|
|
46067
46268
|
}
|
|
46068
46269
|
|
|
46270
|
+
// src/history/history.ts
|
|
46271
|
+
init_buffer();
|
|
46272
|
+
import * as anchor7 from "@anchor-lang/core";
|
|
46273
|
+
import {
|
|
46274
|
+
accountOffsets as accountOffsets2,
|
|
46275
|
+
marketAddress as marketAddress6,
|
|
46276
|
+
transferAddress as transferAddress3
|
|
46277
|
+
} from "@depthhq/bindings";
|
|
46278
|
+
import { PublicKey as PublicKey8 } from "@solana/web3.js";
|
|
46279
|
+
|
|
46280
|
+
// src/history/replay.ts
|
|
46281
|
+
function replayFill(state, fill, fundingIndex, maker = false) {
|
|
46282
|
+
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))
|
|
46283
|
+
throw new Error("A complete private execution is required for history");
|
|
46284
|
+
const side = maker ? -fill.side : fill.side;
|
|
46285
|
+
const delta = side * fill.size;
|
|
46286
|
+
const old = state.position;
|
|
46287
|
+
const next = old + delta;
|
|
46288
|
+
const absolute = (value2) => value2 < 0n ? -value2 : value2;
|
|
46289
|
+
const closing = old !== 0n && old > 0n !== delta > 0n;
|
|
46290
|
+
const size = closing ? fill.size < absolute(old) ? fill.size : absolute(old) : 0n;
|
|
46291
|
+
const gross = (old > 0n ? 1n : -1n) * size * (fill.executionPriceE8 - state.entryPriceE8) / 100000000000n;
|
|
46292
|
+
const funding = old * (fundingIndex - state.fundingCheckpoint) / 100000000000n;
|
|
46293
|
+
const fee = maker ? -fill.makerRebate : fill.fee;
|
|
46294
|
+
const cash = gross - funding - fee;
|
|
46295
|
+
const collateral = state.collateral === undefined ? undefined : state.collateral + cash;
|
|
46296
|
+
if (collateral !== undefined && collateral < 0n)
|
|
46297
|
+
throw new Error("Execution history does not conserve collateral");
|
|
46298
|
+
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);
|
|
46299
|
+
let pnl;
|
|
46300
|
+
if (closing) {
|
|
46301
|
+
const position = {
|
|
46302
|
+
id: "history",
|
|
46303
|
+
status: "ready",
|
|
46304
|
+
slot: fill.slot,
|
|
46305
|
+
version: 0n,
|
|
46306
|
+
...state
|
|
46307
|
+
};
|
|
46308
|
+
pnl = positionPnl(position, fill.executionPriceE8, fundingIndex, {
|
|
46309
|
+
...fill,
|
|
46310
|
+
side,
|
|
46311
|
+
fee: maker ? 0n : fee
|
|
46312
|
+
});
|
|
46313
|
+
if (maker) {
|
|
46314
|
+
pnl = {
|
|
46315
|
+
...pnl,
|
|
46316
|
+
fee,
|
|
46317
|
+
net: cash,
|
|
46318
|
+
returnBps: state.collateral !== undefined && state.collateral > 0n ? cash * 10000n / state.collateral : null
|
|
46319
|
+
};
|
|
46320
|
+
}
|
|
46321
|
+
}
|
|
46322
|
+
return {
|
|
46323
|
+
state: {
|
|
46324
|
+
position: next,
|
|
46325
|
+
entryPriceE8,
|
|
46326
|
+
fundingCheckpoint: fundingIndex,
|
|
46327
|
+
collateral
|
|
46328
|
+
},
|
|
46329
|
+
pnl
|
|
46330
|
+
};
|
|
46331
|
+
}
|
|
46332
|
+
function replayMargin(state, amount, toMarket) {
|
|
46333
|
+
if (amount < 0n)
|
|
46334
|
+
throw new Error("Margin history contains a negative amount");
|
|
46335
|
+
const collateral = state.collateral === undefined ? undefined : state.collateral + (toMarket ? amount : -amount);
|
|
46336
|
+
if (collateral !== undefined && collateral < 0n)
|
|
46337
|
+
throw new Error("Margin history does not conserve collateral");
|
|
46338
|
+
return { ...state, collateral };
|
|
46339
|
+
}
|
|
46340
|
+
|
|
46341
|
+
// src/history/history.ts
|
|
46342
|
+
class ExecutionHistory {
|
|
46343
|
+
program;
|
|
46344
|
+
connection;
|
|
46345
|
+
owner;
|
|
46346
|
+
requestView;
|
|
46347
|
+
views = new Map;
|
|
46348
|
+
fills = new Map;
|
|
46349
|
+
transactions = new Map;
|
|
46350
|
+
constructor(program, connection, owner, requestView) {
|
|
46351
|
+
this.program = program;
|
|
46352
|
+
this.connection = connection;
|
|
46353
|
+
this.owner = owner;
|
|
46354
|
+
this.requestView = requestView;
|
|
46355
|
+
}
|
|
46356
|
+
orderAddress(trader, nonce) {
|
|
46357
|
+
return PublicKey8.findProgramAddressSync([
|
|
46358
|
+
Buffer2.from("order"),
|
|
46359
|
+
marketAddress6(this.program.programId).toBuffer(),
|
|
46360
|
+
trader.toBuffer(),
|
|
46361
|
+
nonce.toArrayLike(Buffer2, "le", 8)
|
|
46362
|
+
], this.program.programId)[0];
|
|
46363
|
+
}
|
|
46364
|
+
async fill(id) {
|
|
46365
|
+
const key = id.toBase58();
|
|
46366
|
+
if (this.fills.has(key) && !this.views.has(key))
|
|
46367
|
+
return this.fills.get(key);
|
|
46368
|
+
if (!this.views.has(key))
|
|
46369
|
+
this.views.set(key, this.requestView(id));
|
|
46370
|
+
let view;
|
|
46371
|
+
try {
|
|
46372
|
+
view = await this.views.get(key);
|
|
46373
|
+
} catch (error) {
|
|
46374
|
+
this.views.delete(key);
|
|
46375
|
+
throw error;
|
|
46376
|
+
}
|
|
46377
|
+
const result = this.fills.get(key) ?? await view.wait({ timeoutMs: 180000 });
|
|
46378
|
+
if (result.status === "stale") {
|
|
46379
|
+
await view.close();
|
|
46380
|
+
this.views.delete(key);
|
|
46381
|
+
throw new Error("Historical private execution changed; retry with the same wallet");
|
|
46382
|
+
}
|
|
46383
|
+
if (result.status !== "ready")
|
|
46384
|
+
throw new Error("Historical private execution is still pending; retry with the same wallet");
|
|
46385
|
+
this.fills.set(key, result);
|
|
46386
|
+
try {
|
|
46387
|
+
await view.close();
|
|
46388
|
+
} catch (error) {
|
|
46389
|
+
if (await this.connection.getAccountInfo(view.id, "confirmed"))
|
|
46390
|
+
throw error;
|
|
46391
|
+
}
|
|
46392
|
+
this.views.delete(key);
|
|
46393
|
+
return result;
|
|
46394
|
+
}
|
|
46395
|
+
async execution(nonce) {
|
|
46396
|
+
if (nonce < 0n || nonce > (1n << 64n) - 1n)
|
|
46397
|
+
throw new RangeError("Trade nonce is invalid");
|
|
46398
|
+
const target = this.orderAddress(this.owner, new anchor7.BN(nonce.toString()));
|
|
46399
|
+
const market = marketAddress6(this.program.programId);
|
|
46400
|
+
const scans = await Promise.all([
|
|
46401
|
+
this.scan("orderRecord", accountOffsets2.OrderRecord.trader),
|
|
46402
|
+
this.scan("orderRecord", accountOffsets2.OrderRecord.maker),
|
|
46403
|
+
this.scan("marginTransfer", accountOffsets2.MarginTransfer.owner)
|
|
46404
|
+
]);
|
|
46405
|
+
const orders = new Map;
|
|
46406
|
+
for (const account of [...scans[0], ...scans[1]]) {
|
|
46407
|
+
const state2 = this.program.coder.accounts.decode("orderRecord", account.account.data);
|
|
46408
|
+
if (!state2.market.equals(market) || !state2.trader.equals(this.owner) && !state2.maker.equals(this.owner) || !account.pubkey.equals(this.orderAddress(state2.trader, state2.nonce)))
|
|
46409
|
+
throw new Error("Historical order identity is invalid");
|
|
46410
|
+
if ("filled" in state2.status)
|
|
46411
|
+
orders.set(account.pubkey.toBase58(), { id: account.pubkey, state: state2 });
|
|
46412
|
+
}
|
|
46413
|
+
const selected = orders.get(target.toBase58());
|
|
46414
|
+
if (!selected || !("trade" in selected.state.kind) || !selected.state.trader.equals(this.owner))
|
|
46415
|
+
throw new Error("Historical trade is not a filled execution by this wallet");
|
|
46416
|
+
const targetTx = await this.settlement(target);
|
|
46417
|
+
const events2 = [];
|
|
46418
|
+
for (const order of orders.values()) {
|
|
46419
|
+
const version = order.state.trader.equals(this.owner) ? order.state.traderVersion : order.state.makerVersion;
|
|
46420
|
+
if (version && selected.state.traderVersion && version.gt(selected.state.traderVersion))
|
|
46421
|
+
continue;
|
|
46422
|
+
const transaction = order.id.equals(target) ? targetTx : await this.settlement(order.id);
|
|
46423
|
+
if (transaction.slot <= targetTx.slot)
|
|
46424
|
+
events2.push({ id: order.id, order: order.state, transaction });
|
|
46425
|
+
}
|
|
46426
|
+
for (const account of scans[2]) {
|
|
46427
|
+
const state2 = this.program.coder.accounts.decode("marginTransfer", account.account.data);
|
|
46428
|
+
if (!state2.owner.equals(this.owner) || !state2.market.equals(market) || !account.pubkey.equals(transferAddress3(this.owner, BigInt(state2.nonce.toString()), this.program.programId)))
|
|
46429
|
+
throw new Error("Historical margin identity is invalid");
|
|
46430
|
+
if (!("settled" in state2.status) && (state2.toMarket || !("escrow" in state2.status) && !("crediting" in state2.status)) || state2.amount.isZero())
|
|
46431
|
+
continue;
|
|
46432
|
+
const key = account.pubkey.toBase58();
|
|
46433
|
+
const transaction = this.transactions.get(key) ?? await receiptTransaction(this.connection, this.program, account.pubkey, state2.toMarket ? ["creditMarketCallback"] : ["debitMarketV2Callback", "debitMarketCallback"]);
|
|
46434
|
+
this.transactions.set(key, transaction);
|
|
46435
|
+
if (transaction.slot <= targetTx.slot)
|
|
46436
|
+
events2.push({ id: account.pubkey, transfer: state2, transaction });
|
|
46437
|
+
}
|
|
46438
|
+
const indexes = new Map;
|
|
46439
|
+
const counts = new Map;
|
|
46440
|
+
for (const event of events2)
|
|
46441
|
+
counts.set(event.transaction.slot, (counts.get(event.transaction.slot) ?? 0) + 1);
|
|
46442
|
+
for (const [slot, count] of counts)
|
|
46443
|
+
if (count > 1) {
|
|
46444
|
+
const block = await this.connection.getBlockSignatures(slot, "confirmed");
|
|
46445
|
+
if (!block)
|
|
46446
|
+
throw new Error("Block ordering is unavailable; use an archival RPC for execution history");
|
|
46447
|
+
indexes.set(slot, new Map(block.signatures.map((signature, index) => [signature, index])));
|
|
46448
|
+
if (events2.some((event) => event.transaction.slot === slot && !indexes.get(slot).has(event.transaction.signature)))
|
|
46449
|
+
throw new Error("Historical transaction is missing from its canonical block");
|
|
46450
|
+
}
|
|
46451
|
+
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));
|
|
46452
|
+
let state = {
|
|
46453
|
+
position: 0n,
|
|
46454
|
+
entryPriceE8: 0n,
|
|
46455
|
+
fundingCheckpoint: 0n,
|
|
46456
|
+
collateral: 0n
|
|
46457
|
+
};
|
|
46458
|
+
for (const event of events2) {
|
|
46459
|
+
if ("transfer" in event) {
|
|
46460
|
+
state = replayMargin(state, BigInt(event.transfer.amount.toString()), event.transfer.toMarket);
|
|
46461
|
+
continue;
|
|
46462
|
+
}
|
|
46463
|
+
if ("liquidation" in event.order.kind) {
|
|
46464
|
+
if (!event.order.trader.equals(this.owner))
|
|
46465
|
+
throw new Error("Historical backstop exposure requires an authorized historical position view");
|
|
46466
|
+
state = {
|
|
46467
|
+
position: 0n,
|
|
46468
|
+
entryPriceE8: 0n,
|
|
46469
|
+
fundingCheckpoint: BigInt(event.order.fundingIndex.toString())
|
|
46470
|
+
};
|
|
46471
|
+
continue;
|
|
46472
|
+
}
|
|
46473
|
+
const fill = await this.fill(event.id);
|
|
46474
|
+
const result = replayFill(state, fill, BigInt(event.order.fundingIndex.toString()), event.order.maker.equals(this.owner));
|
|
46475
|
+
state = result.state;
|
|
46476
|
+
if (event.id.equals(target))
|
|
46477
|
+
return { id: target, fill, pnl: result.pnl, transaction: targetTx };
|
|
46478
|
+
}
|
|
46479
|
+
throw new Error("Historical execution could not be reconciled");
|
|
46480
|
+
}
|
|
46481
|
+
async settlement(id) {
|
|
46482
|
+
const key = id.toBase58();
|
|
46483
|
+
const cached = this.transactions.get(key);
|
|
46484
|
+
if (cached)
|
|
46485
|
+
return { ...cached, orderId: id };
|
|
46486
|
+
const result = await settlementTransaction(this.connection, this.program, id, { orderId: id });
|
|
46487
|
+
this.transactions.set(key, result);
|
|
46488
|
+
return result;
|
|
46489
|
+
}
|
|
46490
|
+
async scan(name2, offset2) {
|
|
46491
|
+
const accounts2 = await this.connection.getProgramAccounts(this.program.programId, {
|
|
46492
|
+
commitment: "confirmed",
|
|
46493
|
+
filters: [
|
|
46494
|
+
{ memcmp: this.program.coder.accounts.memcmp(name2) },
|
|
46495
|
+
{ memcmp: { offset: offset2, bytes: this.owner.toBase58() } }
|
|
46496
|
+
]
|
|
46497
|
+
});
|
|
46498
|
+
if (accounts2.some((item) => !item.account.owner.equals(this.program.programId)))
|
|
46499
|
+
throw new Error("History account owner is invalid");
|
|
46500
|
+
return accounts2;
|
|
46501
|
+
}
|
|
46502
|
+
}
|
|
46503
|
+
|
|
46069
46504
|
// src/trade/amount.ts
|
|
46070
46505
|
function resolveAmount(selector, available, name2) {
|
|
46071
46506
|
u64(available, "available");
|
|
@@ -46119,7 +46554,7 @@ function tradeLimit(input, direction, oraclePriceE8) {
|
|
|
46119
46554
|
}
|
|
46120
46555
|
|
|
46121
46556
|
// src/trade/flow.ts
|
|
46122
|
-
import { transferAddress as
|
|
46557
|
+
import { transferAddress as transferAddress4 } from "@depthhq/bindings";
|
|
46123
46558
|
|
|
46124
46559
|
class TradeFlow {
|
|
46125
46560
|
client;
|
|
@@ -46133,7 +46568,7 @@ class TradeFlow {
|
|
|
46133
46568
|
throw new RangeError("clientNonce must be an unsigned 64-bit bigint");
|
|
46134
46569
|
}
|
|
46135
46570
|
this.id = client.trade.operation(nonce).id;
|
|
46136
|
-
this.allocationId =
|
|
46571
|
+
this.allocationId = transferAddress4(client.options.wallet.publicKey, nonce, client.program.programId);
|
|
46137
46572
|
}
|
|
46138
46573
|
async status() {
|
|
46139
46574
|
const [order, allocation] = await this.client.options.connection.getMultipleAccountsInfo([this.id, this.allocationId], "confirmed");
|
|
@@ -46329,10 +46764,10 @@ class DepthView {
|
|
|
46329
46764
|
|
|
46330
46765
|
// src/client/client.ts
|
|
46331
46766
|
function pda(seeds, programId = DEPTH_PROGRAM_ID7) {
|
|
46332
|
-
return
|
|
46767
|
+
return PublicKey9.findProgramAddressSync(seeds, programId)[0];
|
|
46333
46768
|
}
|
|
46334
46769
|
function nonce() {
|
|
46335
|
-
return new
|
|
46770
|
+
return new anchor8.BN(randomBytes3(8), "le");
|
|
46336
46771
|
}
|
|
46337
46772
|
function enumName2(value2) {
|
|
46338
46773
|
return Object.keys(value2)[0] ?? "unknown";
|
|
@@ -46343,7 +46778,7 @@ class DepthClient {
|
|
|
46343
46778
|
program;
|
|
46344
46779
|
provider;
|
|
46345
46780
|
position;
|
|
46346
|
-
marketAddress =
|
|
46781
|
+
marketAddress = marketAddress7();
|
|
46347
46782
|
protocolAddress = protocolAddress4();
|
|
46348
46783
|
mxeAddress = getMXEAccAddress(DEPTH_PROGRAM_ID7);
|
|
46349
46784
|
get catalog() {
|
|
@@ -46358,17 +46793,21 @@ class DepthClient {
|
|
|
46358
46793
|
get recovery() {
|
|
46359
46794
|
return new DepthRecovery(this.program, this.options.connection, this.options.wallet.publicKey);
|
|
46360
46795
|
}
|
|
46796
|
+
historyClient;
|
|
46797
|
+
get history() {
|
|
46798
|
+
return this.historyClient ??= new ExecutionHistory(this.program, this.options.connection, this.options.wallet.publicKey, (id) => this.requestFillView(id));
|
|
46799
|
+
}
|
|
46361
46800
|
constructor(options) {
|
|
46362
46801
|
this.options = options;
|
|
46363
46802
|
this.provider = new DepthProvider(options.connection, options.wallet, {
|
|
46364
46803
|
commitment: "confirmed",
|
|
46365
46804
|
preflightCommitment: "confirmed"
|
|
46366
46805
|
});
|
|
46367
|
-
this.program = new
|
|
46806
|
+
this.program = new anchor8.Program(DEPTH_IDL3, this.provider);
|
|
46368
46807
|
this.position = this.positionActions();
|
|
46369
46808
|
}
|
|
46370
46809
|
static async create(options) {
|
|
46371
|
-
const appId = typeof options.appId === "string" ? new
|
|
46810
|
+
const appId = typeof options.appId === "string" ? new PublicKey9(options.appId) : options.appId;
|
|
46372
46811
|
const resolved = {
|
|
46373
46812
|
...options,
|
|
46374
46813
|
...await resolveConnection(options),
|
|
@@ -46472,7 +46911,7 @@ class DepthClient {
|
|
|
46472
46911
|
}
|
|
46473
46912
|
async requestFillView(order) {
|
|
46474
46913
|
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")
|
|
46914
|
+
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
46915
|
throw new Error("Filled trade does not belong to this wallet and market");
|
|
46477
46916
|
const viewNonce = nonce();
|
|
46478
46917
|
const view = pda([
|
|
@@ -46586,7 +47025,7 @@ class DepthClient {
|
|
|
46586
47025
|
return this.funding.release(amount, clientNonce ?? BigInt(nonce().toString()));
|
|
46587
47026
|
}
|
|
46588
47027
|
async depositRequest(sourceOrAmount, amount, clientNonce) {
|
|
46589
|
-
if (sourceOrAmount instanceof
|
|
47028
|
+
if (sourceOrAmount instanceof PublicKey9) {
|
|
46590
47029
|
if (amount === undefined || clientNonce === undefined)
|
|
46591
47030
|
throw new RangeError("Source deposits require amount and client nonce");
|
|
46592
47031
|
return this.funding.deposit(sourceOrAmount, amount, clientNonce);
|
|
@@ -46597,7 +47036,7 @@ class DepthClient {
|
|
|
46597
47036
|
return this.funding.deposit(source, sourceOrAmount, amount ?? BigInt(nonce().toString()));
|
|
46598
47037
|
}
|
|
46599
47038
|
async withdrawRequest(destinationOrAmount, amount, clientNonce) {
|
|
46600
|
-
if (destinationOrAmount instanceof
|
|
47039
|
+
if (destinationOrAmount instanceof PublicKey9) {
|
|
46601
47040
|
if (amount === undefined || clientNonce === undefined)
|
|
46602
47041
|
throw new RangeError("Destination withdrawals require amount and client nonce");
|
|
46603
47042
|
return this.funding.withdraw(destinationOrAmount, amount, clientNonce);
|
|
@@ -46612,6 +47051,8 @@ class DepthClient {
|
|
|
46612
47051
|
}
|
|
46613
47052
|
accountActions() {
|
|
46614
47053
|
const actions = {
|
|
47054
|
+
detail: (item) => new FundingDiscovery(this.program, this.options.connection, this.options.wallet.publicKey).detail(item),
|
|
47055
|
+
transaction: (item) => new FundingDiscovery(this.program, this.options.connection, this.options.wallet.publicKey).transaction(item),
|
|
46615
47056
|
history: (options) => new FundingDiscovery(this.program, this.options.connection, this.options.wallet.publicKey).history(options),
|
|
46616
47057
|
pending: (options) => new FundingDiscovery(this.program, this.options.connection, this.options.wallet.publicKey).pending(options),
|
|
46617
47058
|
cancelOpen: () => this.funding.cancelOpenBalance(),
|
|
@@ -46646,6 +47087,23 @@ class DepthClient {
|
|
|
46646
47087
|
addMargin: (amount, clientNonce) => typeof amount === "bigint" && clientNonce !== undefined ? this.funding.allocate(amount, clientNonce) : this.allocateRequest({ marketId: SOL_USD_MARKET_ID3, amount }, clientNonce),
|
|
46647
47088
|
removeMargin: (amount, clientNonce) => typeof amount === "bigint" && clientNonce !== undefined ? this.funding.release(amount, clientNonce) : this.releaseRequest({ marketId: SOL_USD_MARKET_ID3, amount }, clientNonce),
|
|
46648
47089
|
open: async () => this.funding.openMarket(),
|
|
47090
|
+
transaction: () => settlementTransaction(this.options.connection, this.program, address2, {
|
|
47091
|
+
trader: this.options.wallet.publicKey,
|
|
47092
|
+
market: this.marketAddress
|
|
47093
|
+
}),
|
|
47094
|
+
pnl: async () => {
|
|
47095
|
+
const position = await this.positionActions(id).summary();
|
|
47096
|
+
const [market, account] = await Promise.all([
|
|
47097
|
+
this.market(),
|
|
47098
|
+
this.read("MarketAccount", address2)
|
|
47099
|
+
]);
|
|
47100
|
+
const age = Math.floor(Date.now() / 1000) - market.state.oracleTimestamp.toNumber();
|
|
47101
|
+
if (age < 0 || age > market.state.config.maxOracleAgeSeconds)
|
|
47102
|
+
throw new Error("A fresh oracle price is required to value this position");
|
|
47103
|
+
if (position.version !== BigInt(account.version.toString()) || enumName2(account.status) !== "ready")
|
|
47104
|
+
throw new Error("The position changed during valuation; refresh its private view");
|
|
47105
|
+
return positionPnl(position, BigInt(market.state.oraclePriceE8.toString()), BigInt(market.state.fundingIndex.toString()));
|
|
47106
|
+
},
|
|
46649
47107
|
summary: async (options = {
|
|
46650
47108
|
timeoutMs: 180000
|
|
46651
47109
|
}) => {
|
|
@@ -46700,7 +47158,12 @@ class DepthClient {
|
|
|
46700
47158
|
reduce: (input) => this.submitTrade(input, "reduce"),
|
|
46701
47159
|
close: (input) => this.submitTrade(input, "close"),
|
|
46702
47160
|
reverse: (input) => this.submitTrade(input, "reverse"),
|
|
46703
|
-
operation: (clientNonce) => new DepthOperation(this.orderAddress(clientNonce), undefined, this.program, this.options.connection, (order) => this.requestFillView(order))
|
|
47161
|
+
operation: (clientNonce) => new DepthOperation(this.orderAddress(clientNonce), undefined, this.program, this.options.connection, (order) => this.requestFillView(order), undefined, async () => {
|
|
47162
|
+
const detail = await this.history.execution(clientNonce);
|
|
47163
|
+
if (!detail.pnl)
|
|
47164
|
+
throw new Error("This execution does not close any exposure");
|
|
47165
|
+
return detail.pnl;
|
|
47166
|
+
}),
|
|
46704
47167
|
flow: (clientNonce) => new TradeFlow(this, clientNonce),
|
|
46705
47168
|
unpairedAllocations: (options) => new FundingDiscovery(this.program, this.options.connection, this.options.wallet.publicKey).unpairedAllocations(options)
|
|
46706
47169
|
};
|
|
@@ -46852,7 +47315,7 @@ class DepthClient {
|
|
|
46852
47315
|
}), inputNonce);
|
|
46853
47316
|
const offset2 = nonce();
|
|
46854
47317
|
const queue = await this.queue("match_order", offset2);
|
|
46855
|
-
const signature = await this.program.methods.submitOrder(offset2, orderNonce, appId, app.feeBps, app.version, new
|
|
47318
|
+
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
47319
|
...queue,
|
|
46857
47320
|
trader: this.options.wallet.publicKey,
|
|
46858
47321
|
protocol: this.protocolAddress,
|
|
@@ -46873,7 +47336,7 @@ class DepthClient {
|
|
|
46873
47336
|
isWritable: true
|
|
46874
47337
|
}
|
|
46875
47338
|
]).rpc({ commitment: "confirmed" }).catch((error) => submissionError(order.toBase58(), error));
|
|
46876
|
-
return new DepthOperation(order, signature, this.program, this.options.connection, (id) => this.requestFillView(id));
|
|
47339
|
+
return new DepthOperation(order, signature, this.program, this.options.connection, (id) => this.requestFillView(id), position);
|
|
46877
47340
|
}
|
|
46878
47341
|
validateTrade(market, protocol, account, app, appId, intent = "increase", deadline) {
|
|
46879
47342
|
const now = Math.floor(Date.now() / 1000);
|
|
@@ -47043,6 +47506,7 @@ export {
|
|
|
47043
47506
|
verifyDeployment,
|
|
47044
47507
|
resolveConnection,
|
|
47045
47508
|
resolveAmount,
|
|
47509
|
+
positionPnl,
|
|
47046
47510
|
manifestBytes,
|
|
47047
47511
|
create_depth_data,
|
|
47048
47512
|
createDepth as create_depth,
|
|
@@ -47056,6 +47520,7 @@ export {
|
|
|
47056
47520
|
MarketCatalog,
|
|
47057
47521
|
FundingDiscovery,
|
|
47058
47522
|
FundingClient,
|
|
47523
|
+
ExecutionHistory,
|
|
47059
47524
|
DepthView,
|
|
47060
47525
|
DepthRecovery,
|
|
47061
47526
|
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
|
-
|
|
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;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@depthhq/sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
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/schema": "0.1.1",
|
|
48
|
+
"@depthhq/bindings": "0.1.1"
|
|
49
49
|
},
|
|
50
50
|
"scripts": {
|
|
51
51
|
"build": "node ../../scripts/build-package.mjs sdk",
|