@depthhq/sdk 0.1.2 → 0.1.3
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/funding.d.ts +2 -1
- package/dist/account/funding.js +4 -2
- package/dist/chain/provider.d.ts +4 -1
- package/dist/client/client.d.ts +9 -1
- package/dist/client/types.d.ts +4 -0
- package/dist/index.js +318 -104
- package/dist/view/cache.d.ts +31 -0
- package/dist/view/view.d.ts +4 -0
- package/dist/view/view.js +17 -2
- package/package.json +4 -1
|
@@ -7,11 +7,12 @@ export declare class FundingClient {
|
|
|
7
7
|
readonly connection: Connection;
|
|
8
8
|
readonly owner: PublicKey;
|
|
9
9
|
private readonly queue;
|
|
10
|
+
readonly settlement: "keeper" | "wallet";
|
|
10
11
|
readonly market: PublicKey;
|
|
11
12
|
readonly protocol: PublicKey;
|
|
12
13
|
readonly balance: PublicKey;
|
|
13
14
|
readonly marketAccount: PublicKey;
|
|
14
|
-
constructor(program: anchor.Program, connection: Connection, owner: PublicKey, queue: Queue);
|
|
15
|
+
constructor(program: anchor.Program, connection: Connection, owner: PublicKey, queue: Queue, settlement?: "keeper" | "wallet");
|
|
15
16
|
private assertOwner;
|
|
16
17
|
read<T>(name: string, address: PublicKey): Promise<T | undefined>;
|
|
17
18
|
private recoveryKey;
|
package/dist/account/funding.js
CHANGED
|
@@ -76,15 +76,17 @@ class FundingClient {
|
|
|
76
76
|
connection;
|
|
77
77
|
owner;
|
|
78
78
|
queue;
|
|
79
|
+
settlement;
|
|
79
80
|
market;
|
|
80
81
|
protocol;
|
|
81
82
|
balance;
|
|
82
83
|
marketAccount;
|
|
83
|
-
constructor(program, connection, owner, queue) {
|
|
84
|
+
constructor(program, connection, owner, queue, settlement = "wallet") {
|
|
84
85
|
this.program = program;
|
|
85
86
|
this.connection = connection;
|
|
86
87
|
this.owner = owner;
|
|
87
88
|
this.queue = queue;
|
|
89
|
+
this.settlement = settlement;
|
|
88
90
|
this.market = marketAddress(program.programId);
|
|
89
91
|
this.protocol = protocolAddress(program.programId);
|
|
90
92
|
this.balance = balanceAddress(owner, program.programId);
|
|
@@ -418,7 +420,7 @@ class TransferHandle {
|
|
|
418
420
|
return true;
|
|
419
421
|
if (transfer.state === "rejected" || transfer.state === "refunded" || transfer.state === "cancelled")
|
|
420
422
|
throw new DepthError("MARGIN_REJECTED", "confirmation", `Margin transfer ${transfer.state}`, false, "Read the receipt and private account before retrying", this.id.toBase58());
|
|
421
|
-
if (transfer.state === "escrow") {
|
|
423
|
+
if (transfer.state === "escrow" && this.client.settlement === "wallet") {
|
|
422
424
|
try {
|
|
423
425
|
await this.settle();
|
|
424
426
|
} catch (error) {
|
package/dist/chain/provider.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import * as anchor from "@anchor-lang/core";
|
|
2
|
-
import { Transaction } from "@solana/web3.js";
|
|
2
|
+
import { PublicKey, Transaction, TransactionInstruction } from "@solana/web3.js";
|
|
3
3
|
export declare function applyDepthComputeBudget(transaction: Transaction): void;
|
|
4
4
|
export declare class DepthProvider extends anchor.AnchorProvider {
|
|
5
|
+
private readonly cleanup;
|
|
6
|
+
deferClose(id: PublicKey, instruction: TransactionInstruction): void;
|
|
7
|
+
appendCleanup(transaction: Transaction): Promise<string[]>;
|
|
5
8
|
sendAndConfirm(transaction: Parameters<anchor.AnchorProvider["sendAndConfirm"]>[0], signers?: Parameters<anchor.AnchorProvider["sendAndConfirm"]>[1], options?: Parameters<anchor.AnchorProvider["sendAndConfirm"]>[2]): Promise<string>;
|
|
6
9
|
}
|
package/dist/client/client.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as anchor from "@anchor-lang/core";
|
|
2
2
|
import { SOL_USD_MARKET_ID } from "@depthhq/bindings";
|
|
3
3
|
import { PublicKey } from "@solana/web3.js";
|
|
4
|
+
import { DepthProvider } from "../chain/provider.js";
|
|
4
5
|
import { AppAdmin } from "../app/app.js";
|
|
5
6
|
import { MarketCatalog } from "../catalog/catalog.js";
|
|
6
7
|
import { FundingDiscovery } from "../account/discovery.js";
|
|
@@ -16,7 +17,9 @@ import type { CloseInput, DepthOptions, ResolvedDepthOptions, MarketState, Reduc
|
|
|
16
17
|
export declare class DepthClient {
|
|
17
18
|
readonly options: ResolvedDepthOptions;
|
|
18
19
|
readonly program: anchor.Program;
|
|
19
|
-
readonly provider:
|
|
20
|
+
readonly provider: DepthProvider;
|
|
21
|
+
private readonly views;
|
|
22
|
+
private readonly viewReads;
|
|
20
23
|
readonly position: ReturnType<DepthClient["positionActions"]>;
|
|
21
24
|
readonly marketAddress: anchor.web3.PublicKey;
|
|
22
25
|
readonly protocolAddress: anchor.web3.PublicKey;
|
|
@@ -133,7 +136,12 @@ export declare class DepthClient {
|
|
|
133
136
|
}>;
|
|
134
137
|
};
|
|
135
138
|
private orderAddress;
|
|
139
|
+
private deferViewClose;
|
|
140
|
+
private viewState;
|
|
141
|
+
private summaryView;
|
|
142
|
+
private readSummaryView;
|
|
136
143
|
private submitTrade;
|
|
144
|
+
private waitForMarket;
|
|
137
145
|
private validateTrade;
|
|
138
146
|
}
|
|
139
147
|
export declare function createDepth(options: DepthOptions): Promise<DepthClient>;
|
package/dist/client/types.d.ts
CHANGED
|
@@ -11,10 +11,14 @@ export type DepthWallet = {
|
|
|
11
11
|
export type DepthOptions = ConnectionOptions & {
|
|
12
12
|
appId?: PublicKey | string;
|
|
13
13
|
wallet: DepthWallet;
|
|
14
|
+
privateViews?: "memory" | "device";
|
|
15
|
+
settlement?: "keeper" | "wallet";
|
|
14
16
|
};
|
|
15
17
|
export type ResolvedDepthOptions = ResolvedConnection & {
|
|
16
18
|
appId?: PublicKey;
|
|
17
19
|
wallet: DepthWallet;
|
|
20
|
+
privateViews?: "memory" | "device";
|
|
21
|
+
settlement?: "keeper" | "wallet";
|
|
18
22
|
};
|
|
19
23
|
export type TradeTerms = {
|
|
20
24
|
marketId: typeof SOL_USD_MARKET_ID;
|
package/dist/index.js
CHANGED
|
@@ -43628,7 +43628,7 @@ import {
|
|
|
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 PublicKey10 } from "@solana/web3.js";
|
|
43632
43632
|
|
|
43633
43633
|
// src/chain/random.ts
|
|
43634
43634
|
function randomBytes3(length) {
|
|
@@ -44726,6 +44726,7 @@ import { DEPTH_IDL as DEPTH_IDL2, DEPTH_PROGRAM_ID as DEPTH_PROGRAM_ID3 } from "
|
|
|
44726
44726
|
import {
|
|
44727
44727
|
ComputeBudgetProgram,
|
|
44728
44728
|
SendTransactionError,
|
|
44729
|
+
PublicKey as PublicKey4,
|
|
44729
44730
|
Transaction
|
|
44730
44731
|
} from "@solana/web3.js";
|
|
44731
44732
|
var queuedInstructions = new Set([
|
|
@@ -44768,11 +44769,52 @@ function applyDepthComputeBudget(transaction) {
|
|
|
44768
44769
|
}
|
|
44769
44770
|
|
|
44770
44771
|
class DepthProvider extends anchor3.AnchorProvider {
|
|
44772
|
+
cleanup = new Map;
|
|
44773
|
+
deferClose(id, instruction) {
|
|
44774
|
+
this.cleanup.set(id.toBase58(), instruction);
|
|
44775
|
+
}
|
|
44776
|
+
async appendCleanup(transaction) {
|
|
44777
|
+
if (!this.cleanup.size || transaction.signatures.some((item) => item.signature))
|
|
44778
|
+
return [];
|
|
44779
|
+
const entries = [...this.cleanup.entries()].slice(0, 64);
|
|
44780
|
+
const queued = new Set(entries.map(([, instruction]) => instruction));
|
|
44781
|
+
transaction.instructions = transaction.instructions.filter((instruction) => !queued.has(instruction));
|
|
44782
|
+
const accounts2 = await this.connection.getMultipleAccountsInfo(entries.map(([id]) => new PublicKey4(id)), "confirmed");
|
|
44783
|
+
const added = [];
|
|
44784
|
+
for (let index = 0;index < entries.length; index++) {
|
|
44785
|
+
const [id, instruction] = entries[index];
|
|
44786
|
+
if (!accounts2[index]?.owner.equals(DEPTH_PROGRAM_ID3)) {
|
|
44787
|
+
this.cleanup.delete(id);
|
|
44788
|
+
continue;
|
|
44789
|
+
}
|
|
44790
|
+
const candidate = new Transaction({
|
|
44791
|
+
feePayer: transaction.feePayer ?? this.wallet.publicKey,
|
|
44792
|
+
recentBlockhash: transaction.recentBlockhash ?? PublicKey4.default.toBase58()
|
|
44793
|
+
}).add(...transaction.instructions, instruction);
|
|
44794
|
+
try {
|
|
44795
|
+
candidate.serialize({
|
|
44796
|
+
requireAllSignatures: false,
|
|
44797
|
+
verifySignatures: false
|
|
44798
|
+
});
|
|
44799
|
+
} catch {
|
|
44800
|
+
continue;
|
|
44801
|
+
}
|
|
44802
|
+
transaction.add(instruction);
|
|
44803
|
+
added.push(id);
|
|
44804
|
+
}
|
|
44805
|
+
return added;
|
|
44806
|
+
}
|
|
44771
44807
|
async sendAndConfirm(transaction, signers, options) {
|
|
44772
|
-
|
|
44808
|
+
let cleanup = [];
|
|
44809
|
+
if (transaction instanceof Transaction) {
|
|
44773
44810
|
applyDepthComputeBudget(transaction);
|
|
44811
|
+
cleanup = await this.appendCleanup(transaction);
|
|
44812
|
+
}
|
|
44774
44813
|
try {
|
|
44775
|
-
|
|
44814
|
+
const signature = await super.sendAndConfirm(transaction, signers, options);
|
|
44815
|
+
for (const id of cleanup)
|
|
44816
|
+
this.cleanup.delete(id);
|
|
44817
|
+
return signature;
|
|
44776
44818
|
} catch (error) {
|
|
44777
44819
|
if (!(error instanceof Error) || !error.message.includes("Unknown action 'undefined'"))
|
|
44778
44820
|
throw error;
|
|
@@ -45023,7 +45065,7 @@ import {
|
|
|
45023
45065
|
transferAddress,
|
|
45024
45066
|
withdrawalAddress
|
|
45025
45067
|
} from "@depthhq/bindings";
|
|
45026
|
-
import { PublicKey as
|
|
45068
|
+
import { PublicKey as PublicKey5 } from "@solana/web3.js";
|
|
45027
45069
|
|
|
45028
45070
|
// src/chain/transaction.ts
|
|
45029
45071
|
init_buffer();
|
|
@@ -45181,7 +45223,7 @@ class FundingDiscovery {
|
|
|
45181
45223
|
const limit = options.limit ?? 20;
|
|
45182
45224
|
if (!Number.isSafeInteger(limit) || limit < 1 || limit > 100)
|
|
45183
45225
|
throw new RangeError("limit must be an integer from 1 to 100");
|
|
45184
|
-
const cursor = options.cursor ? new
|
|
45226
|
+
const cursor = options.cursor ? new PublicKey5(options.cursor).toBase58() : undefined;
|
|
45185
45227
|
const accounts2 = await this.connection.getProgramAccounts(this.program.programId, {
|
|
45186
45228
|
commitment: "confirmed",
|
|
45187
45229
|
dataSlice: { offset: 0, length: 0 },
|
|
@@ -45213,7 +45255,7 @@ class FundingDiscovery {
|
|
|
45213
45255
|
const current = status(state);
|
|
45214
45256
|
if (!state.toMarket || current !== "settled")
|
|
45215
45257
|
return;
|
|
45216
|
-
const orderId =
|
|
45258
|
+
const orderId = PublicKey5.findProgramAddressSync([
|
|
45217
45259
|
Buffer2.from("order"),
|
|
45218
45260
|
state.market.toBuffer(),
|
|
45219
45261
|
this.owner.toBuffer(),
|
|
@@ -45260,7 +45302,7 @@ class FundingDiscovery {
|
|
|
45260
45302
|
const limit = options.limit ?? 20;
|
|
45261
45303
|
if (!Number.isSafeInteger(limit) || limit < 1 || limit > 100)
|
|
45262
45304
|
throw new RangeError("limit must be an integer from 1 to 100");
|
|
45263
|
-
const cursor = options.cursor ? new
|
|
45305
|
+
const cursor = options.cursor ? new PublicKey5(options.cursor).toBase58() : undefined;
|
|
45264
45306
|
const types3 = [
|
|
45265
45307
|
{
|
|
45266
45308
|
name: "depositReceipt",
|
|
@@ -45351,7 +45393,7 @@ class FundingDiscovery {
|
|
|
45351
45393
|
throw new Error("Order changed during discovery");
|
|
45352
45394
|
const bytes = Buffer2.alloc(8);
|
|
45353
45395
|
bytes.writeBigUInt64LE(nonce);
|
|
45354
|
-
canonical =
|
|
45396
|
+
canonical = PublicKey5.findProgramAddressSync([
|
|
45355
45397
|
Buffer2.from("order"),
|
|
45356
45398
|
state.market.toBuffer(),
|
|
45357
45399
|
this.owner.toBuffer(),
|
|
@@ -45437,15 +45479,17 @@ class FundingClient {
|
|
|
45437
45479
|
connection;
|
|
45438
45480
|
owner;
|
|
45439
45481
|
queue;
|
|
45482
|
+
settlement;
|
|
45440
45483
|
market;
|
|
45441
45484
|
protocol;
|
|
45442
45485
|
balance;
|
|
45443
45486
|
marketAccount;
|
|
45444
|
-
constructor(program, connection, owner, queue) {
|
|
45487
|
+
constructor(program, connection, owner, queue, settlement = "wallet") {
|
|
45445
45488
|
this.program = program;
|
|
45446
45489
|
this.connection = connection;
|
|
45447
45490
|
this.owner = owner;
|
|
45448
45491
|
this.queue = queue;
|
|
45492
|
+
this.settlement = settlement;
|
|
45449
45493
|
this.market = marketAddress3(program.programId);
|
|
45450
45494
|
this.protocol = protocolAddress2(program.programId);
|
|
45451
45495
|
this.balance = balanceAddress(owner, program.programId);
|
|
@@ -45779,7 +45823,7 @@ class TransferHandle {
|
|
|
45779
45823
|
return true;
|
|
45780
45824
|
if (transfer.state === "rejected" || transfer.state === "refunded" || transfer.state === "cancelled")
|
|
45781
45825
|
throw new DepthError("MARGIN_REJECTED", "confirmation", `Margin transfer ${transfer.state}`, false, "Read the receipt and private account before retrying", this.id.toBase58());
|
|
45782
|
-
if (transfer.state === "escrow") {
|
|
45826
|
+
if (transfer.state === "escrow" && this.client.settlement === "wallet") {
|
|
45783
45827
|
try {
|
|
45784
45828
|
await this.settle();
|
|
45785
45829
|
} catch (error) {
|
|
@@ -45883,15 +45927,15 @@ async function balanceState(program, connection, owner, address2) {
|
|
|
45883
45927
|
// src/account/token.ts
|
|
45884
45928
|
init_buffer();
|
|
45885
45929
|
import {
|
|
45886
|
-
PublicKey as
|
|
45930
|
+
PublicKey as PublicKey6,
|
|
45887
45931
|
SystemProgram,
|
|
45888
45932
|
Transaction as Transaction2,
|
|
45889
|
-
TransactionInstruction
|
|
45933
|
+
TransactionInstruction as TransactionInstruction2
|
|
45890
45934
|
} from "@solana/web3.js";
|
|
45891
|
-
var tokenProgram = new
|
|
45892
|
-
var associatedProgram = new
|
|
45935
|
+
var tokenProgram = new PublicKey6("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
|
|
45936
|
+
var associatedProgram = new PublicKey6("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL");
|
|
45893
45937
|
function associatedTokenAddress(owner, mint) {
|
|
45894
|
-
return
|
|
45938
|
+
return PublicKey6.findProgramAddressSync([owner.toBuffer(), tokenProgram.toBuffer(), mint.toBuffer()], associatedProgram)[0];
|
|
45895
45939
|
}
|
|
45896
45940
|
function tokenBalance(info, owner, mint) {
|
|
45897
45941
|
if (!info.owner.equals(tokenProgram) || info.data.length < 165 || !info.data.subarray(0, 32).equals(mint.toBuffer()) || !info.data.subarray(32, 64).equals(owner.toBuffer()) || info.data[108] !== 1)
|
|
@@ -45920,7 +45964,7 @@ async function destinationTokenAccount(provider, owner, mint) {
|
|
|
45920
45964
|
const address2 = associatedTokenAddress(owner, mint);
|
|
45921
45965
|
let info = await provider.connection.getAccountInfo(address2, "confirmed");
|
|
45922
45966
|
if (!info) {
|
|
45923
|
-
const instruction = new
|
|
45967
|
+
const instruction = new TransactionInstruction2({
|
|
45924
45968
|
programId: associatedProgram,
|
|
45925
45969
|
data: Buffer2.from([1]),
|
|
45926
45970
|
keys: [
|
|
@@ -45962,7 +46006,7 @@ import {
|
|
|
45962
46006
|
marketAddress as marketAddress4,
|
|
45963
46007
|
SOL_USD_MARKET_ID as SOL_USD_MARKET_ID2
|
|
45964
46008
|
} from "@depthhq/bindings";
|
|
45965
|
-
import { PublicKey as
|
|
46009
|
+
import { PublicKey as PublicKey7 } from "@solana/web3.js";
|
|
45966
46010
|
|
|
45967
46011
|
// src/position/pnl.ts
|
|
45968
46012
|
var scale = 100000000000n;
|
|
@@ -46192,11 +46236,11 @@ class DepthOperation {
|
|
|
46192
46236
|
throw new DepthError(result.status === "pending" ? "FILL_VIEW_PENDING" : "FILL_VIEW_STALE", "confirmation", result.status === "pending" ? "Private fill computation is still pending" : "Private fill view is stale", result.status === "pending", result.status === "pending" ? "Call privateResult again with the same operation" : "Restore this operation and request a fresh fill view", this.id.toBase58());
|
|
46193
46237
|
this.fill = {
|
|
46194
46238
|
...result,
|
|
46195
|
-
positionId: marketAccountAddress2(new
|
|
46239
|
+
positionId: marketAccountAddress2(new PublicKey7(snapshot.owner), this.program.programId)
|
|
46196
46240
|
};
|
|
46197
46241
|
}
|
|
46198
46242
|
try {
|
|
46199
|
-
await this.view.
|
|
46243
|
+
await this.view.deferClose();
|
|
46200
46244
|
} catch (error) {
|
|
46201
46245
|
let remaining;
|
|
46202
46246
|
try {
|
|
@@ -46212,7 +46256,7 @@ class DepthOperation {
|
|
|
46212
46256
|
return this.fill;
|
|
46213
46257
|
}
|
|
46214
46258
|
cleanupError(cause) {
|
|
46215
|
-
return new DepthError("FILL_VIEW_CLEANUP_PENDING", "confirmation", "Private fill was read but
|
|
46259
|
+
return new DepthError("FILL_VIEW_CLEANUP_PENDING", "confirmation", "Private fill was read but receipt cleanup could not be scheduled", true, "Call privateResult again with the same operation to schedule cleanup", this.id.toBase58(), { cause });
|
|
46216
46260
|
}
|
|
46217
46261
|
}
|
|
46218
46262
|
|
|
@@ -46223,22 +46267,22 @@ import {
|
|
|
46223
46267
|
marketAddress as marketAddress5,
|
|
46224
46268
|
protocolAddress as protocolAddress3
|
|
46225
46269
|
} from "@depthhq/bindings";
|
|
46226
|
-
import { PublicKey as
|
|
46270
|
+
import { PublicKey as PublicKey8 } from "@solana/web3.js";
|
|
46227
46271
|
|
|
46228
46272
|
class DepthRecovery {
|
|
46229
46273
|
program;
|
|
46230
46274
|
connection;
|
|
46231
46275
|
owner;
|
|
46232
46276
|
market = marketAddress5();
|
|
46233
|
-
winddown =
|
|
46277
|
+
winddown = PublicKey8.findProgramAddressSync([Buffer2.from("winddown"), this.market.toBuffer()], DEPTH_PROGRAM_ID5)[0];
|
|
46234
46278
|
marketAccount;
|
|
46235
46279
|
claim;
|
|
46236
46280
|
constructor(program, connection, owner) {
|
|
46237
46281
|
this.program = program;
|
|
46238
46282
|
this.connection = connection;
|
|
46239
46283
|
this.owner = owner;
|
|
46240
|
-
this.marketAccount =
|
|
46241
|
-
this.claim =
|
|
46284
|
+
this.marketAccount = PublicKey8.findProgramAddressSync([Buffer2.from("market-account"), this.market.toBuffer(), owner.toBuffer()], DEPTH_PROGRAM_ID5)[0];
|
|
46285
|
+
this.claim = PublicKey8.findProgramAddressSync([Buffer2.from("winddown-claim"), this.marketAccount.toBuffer()], DEPTH_PROGRAM_ID5)[0];
|
|
46242
46286
|
}
|
|
46243
46287
|
async read(address2, name2) {
|
|
46244
46288
|
const result = await this.connection.getAccountInfoAndContext(address2, "confirmed");
|
|
@@ -46328,7 +46372,7 @@ import {
|
|
|
46328
46372
|
marketAddress as marketAddress6,
|
|
46329
46373
|
transferAddress as transferAddress3
|
|
46330
46374
|
} from "@depthhq/bindings";
|
|
46331
|
-
import { PublicKey as
|
|
46375
|
+
import { PublicKey as PublicKey9 } from "@solana/web3.js";
|
|
46332
46376
|
|
|
46333
46377
|
// src/history/replay.ts
|
|
46334
46378
|
function replayFill(state, fill, fundingIndex, maker = false) {
|
|
@@ -46407,7 +46451,7 @@ class ExecutionHistory {
|
|
|
46407
46451
|
this.requestView = requestView;
|
|
46408
46452
|
}
|
|
46409
46453
|
orderAddress(trader, nonce) {
|
|
46410
|
-
return
|
|
46454
|
+
return PublicKey9.findProgramAddressSync([
|
|
46411
46455
|
Buffer2.from("order"),
|
|
46412
46456
|
marketAddress6(this.program.programId).toBuffer(),
|
|
46413
46457
|
trader.toBuffer(),
|
|
@@ -46429,7 +46473,7 @@ class ExecutionHistory {
|
|
|
46429
46473
|
}
|
|
46430
46474
|
const result = this.fills.get(key) ?? await view.wait({ timeoutMs: 180000 });
|
|
46431
46475
|
if (result.status === "stale") {
|
|
46432
|
-
await view.
|
|
46476
|
+
await view.deferClose();
|
|
46433
46477
|
this.views.delete(key);
|
|
46434
46478
|
throw new Error("Historical private execution changed; retry with the same wallet");
|
|
46435
46479
|
}
|
|
@@ -46437,7 +46481,7 @@ class ExecutionHistory {
|
|
|
46437
46481
|
throw new Error("Historical private execution is still pending; retry with the same wallet");
|
|
46438
46482
|
this.fills.set(key, result);
|
|
46439
46483
|
try {
|
|
46440
|
-
await view.
|
|
46484
|
+
await view.deferClose();
|
|
46441
46485
|
} catch (error) {
|
|
46442
46486
|
if (await this.connection.getAccountInfo(view.id, "confirmed"))
|
|
46443
46487
|
throw error;
|
|
@@ -46805,19 +46849,151 @@ class DepthView {
|
|
|
46805
46849
|
await new Promise((resolve) => setTimeout(resolve, Math.min(pollMs, deadline - Date.now())));
|
|
46806
46850
|
}
|
|
46807
46851
|
}
|
|
46852
|
+
async deferClose() {
|
|
46853
|
+
const provider = this.program.provider;
|
|
46854
|
+
if (typeof provider.deferClose !== "function") {
|
|
46855
|
+
await this.close();
|
|
46856
|
+
return;
|
|
46857
|
+
}
|
|
46858
|
+
const snapshot = await this.status();
|
|
46859
|
+
if (snapshot.status === "pending")
|
|
46860
|
+
throw new Error("Private view computation is still pending");
|
|
46861
|
+
const instruction = await this.closeBuilder().instruction();
|
|
46862
|
+
provider.deferClose(this.id, instruction);
|
|
46863
|
+
}
|
|
46864
|
+
closeBuilder() {
|
|
46865
|
+
const builder = this.kind === "balance" ? this.program.methods.closeBalanceView() : this.kind === "market" ? this.program.methods.closeMarketView() : this.kind === "fill" ? this.program.methods.closeFillView() : this.program.methods.closeQuoteView();
|
|
46866
|
+
return builder.accountsPartial({ owner: this.owner, view: this.id });
|
|
46867
|
+
}
|
|
46808
46868
|
async close() {
|
|
46809
46869
|
const snapshot = await this.status();
|
|
46810
46870
|
if (snapshot.status === "pending") {
|
|
46811
46871
|
throw new Error("Private view computation is still pending");
|
|
46812
46872
|
}
|
|
46813
|
-
|
|
46814
|
-
|
|
46873
|
+
return this.closeBuilder().rpc({ commitment: "confirmed" });
|
|
46874
|
+
}
|
|
46875
|
+
}
|
|
46876
|
+
|
|
46877
|
+
// src/view/cache.ts
|
|
46878
|
+
class DeviceViews {
|
|
46879
|
+
database;
|
|
46880
|
+
open() {
|
|
46881
|
+
return this.database ??= new Promise((resolve, reject) => {
|
|
46882
|
+
const request = indexedDB.open("depth-private-views", 1);
|
|
46883
|
+
request.onupgradeneeded = () => {
|
|
46884
|
+
request.result.createObjectStore("keys");
|
|
46885
|
+
request.result.createObjectStore("views");
|
|
46886
|
+
};
|
|
46887
|
+
request.onerror = () => reject(request.error);
|
|
46888
|
+
request.onblocked = () => reject(new Error("Private view storage is blocked"));
|
|
46889
|
+
request.onsuccess = () => resolve(request.result);
|
|
46890
|
+
});
|
|
46891
|
+
}
|
|
46892
|
+
async key(scope, proposed) {
|
|
46893
|
+
const database = await this.open();
|
|
46894
|
+
return new Promise((resolve, reject) => {
|
|
46895
|
+
const transaction = database.transaction("keys", "readwrite");
|
|
46896
|
+
const store = transaction.objectStore("keys");
|
|
46897
|
+
const request = store.get(scope);
|
|
46898
|
+
let value2;
|
|
46899
|
+
request.onsuccess = () => {
|
|
46900
|
+
value2 = request.result ?? proposed;
|
|
46901
|
+
if (!request.result)
|
|
46902
|
+
store.put(value2, scope);
|
|
46903
|
+
};
|
|
46904
|
+
transaction.oncomplete = () => resolve(value2);
|
|
46905
|
+
transaction.onabort = () => reject(transaction.error);
|
|
46906
|
+
transaction.onerror = () => reject(transaction.error);
|
|
46907
|
+
});
|
|
46908
|
+
}
|
|
46909
|
+
async read(id) {
|
|
46910
|
+
const database = await this.open();
|
|
46911
|
+
return new Promise((resolve, reject) => {
|
|
46912
|
+
const transaction = database.transaction("views", "readonly");
|
|
46913
|
+
const request = transaction.objectStore("views").get(id);
|
|
46914
|
+
transaction.oncomplete = () => resolve(request.result);
|
|
46915
|
+
transaction.onabort = () => reject(transaction.error);
|
|
46916
|
+
transaction.onerror = () => reject(transaction.error);
|
|
46917
|
+
});
|
|
46918
|
+
}
|
|
46919
|
+
async write(id, value2) {
|
|
46920
|
+
const database = await this.open();
|
|
46921
|
+
return new Promise((resolve, reject) => {
|
|
46922
|
+
const transaction = database.transaction("views", "readwrite");
|
|
46923
|
+
transaction.objectStore("views").put(value2, id);
|
|
46924
|
+
transaction.oncomplete = () => resolve();
|
|
46925
|
+
transaction.onabort = () => reject(transaction.error);
|
|
46926
|
+
transaction.onerror = () => reject(transaction.error);
|
|
46927
|
+
});
|
|
46928
|
+
}
|
|
46929
|
+
}
|
|
46930
|
+
|
|
46931
|
+
class ViewCache {
|
|
46932
|
+
scope;
|
|
46933
|
+
storage;
|
|
46934
|
+
memory = new Map;
|
|
46935
|
+
key;
|
|
46936
|
+
constructor(scope, storage) {
|
|
46937
|
+
this.scope = scope;
|
|
46938
|
+
this.storage = storage;
|
|
46939
|
+
}
|
|
46940
|
+
encryptionKey() {
|
|
46941
|
+
return this.key ??= crypto.subtle.generateKey({ name: "AES-GCM", length: 256 }, false, [
|
|
46942
|
+
"encrypt",
|
|
46943
|
+
"decrypt"
|
|
46944
|
+
]).then((key) => this.storage.key(this.scope, key));
|
|
46945
|
+
}
|
|
46946
|
+
id(kind, account) {
|
|
46947
|
+
return `${this.scope}:${kind}:${account}`;
|
|
46948
|
+
}
|
|
46949
|
+
async get(kind, account, version) {
|
|
46950
|
+
const id = this.id(kind, account);
|
|
46951
|
+
let snapshot = this.memory.get(id);
|
|
46952
|
+
if (!snapshot && this.storage) {
|
|
46953
|
+
try {
|
|
46954
|
+
const envelope = await this.storage.read(id);
|
|
46955
|
+
if (envelope) {
|
|
46956
|
+
const bytes = await crypto.subtle.decrypt({
|
|
46957
|
+
name: "AES-GCM",
|
|
46958
|
+
iv: envelope.iv,
|
|
46959
|
+
additionalData: new TextEncoder().encode(id)
|
|
46960
|
+
}, await this.encryptionKey(), envelope.data);
|
|
46961
|
+
snapshot = JSON.parse(new TextDecoder().decode(bytes), (_, value2) => value2 && typeof value2 === "object" && typeof value2.$bigint === "string" ? BigInt(value2.$bigint) : value2);
|
|
46962
|
+
}
|
|
46963
|
+
} catch {
|
|
46964
|
+
return;
|
|
46965
|
+
}
|
|
46966
|
+
}
|
|
46967
|
+
if (!snapshot || snapshot.status !== "ready" || snapshot.version !== version || typeof snapshot.id !== "string" || !Number.isSafeInteger(snapshot.slot) || (kind === "balance" ? typeof snapshot.amount !== "bigint" : [
|
|
46968
|
+
"collateral",
|
|
46969
|
+
"reserved",
|
|
46970
|
+
"position",
|
|
46971
|
+
"entryPriceE8",
|
|
46972
|
+
"fundingCheckpoint"
|
|
46973
|
+
].some((field) => typeof snapshot[field] !== "bigint")))
|
|
46974
|
+
return;
|
|
46975
|
+
this.memory.set(id, snapshot);
|
|
46976
|
+
return { ...snapshot };
|
|
46977
|
+
}
|
|
46978
|
+
async set(kind, account, snapshot) {
|
|
46979
|
+
if (snapshot.status !== "ready")
|
|
46980
|
+
return;
|
|
46981
|
+
const id = this.id(kind, account);
|
|
46982
|
+
this.memory.set(id, { ...snapshot });
|
|
46983
|
+
if (!this.storage)
|
|
46984
|
+
return;
|
|
46985
|
+
try {
|
|
46986
|
+
const iv = crypto.getRandomValues(new Uint8Array(12));
|
|
46987
|
+
const bytes = new TextEncoder().encode(JSON.stringify(snapshot, (_, value2) => typeof value2 === "bigint" ? { $bigint: value2.toString() } : value2));
|
|
46988
|
+
const data = await crypto.subtle.encrypt({ name: "AES-GCM", iv, additionalData: new TextEncoder().encode(id) }, await this.encryptionKey(), bytes);
|
|
46989
|
+
await this.storage.write(id, { iv, data });
|
|
46990
|
+
} catch {}
|
|
46815
46991
|
}
|
|
46816
46992
|
}
|
|
46817
46993
|
|
|
46818
46994
|
// src/client/client.ts
|
|
46819
46995
|
function pda(seeds, programId = DEPTH_PROGRAM_ID7) {
|
|
46820
|
-
return
|
|
46996
|
+
return PublicKey10.findProgramAddressSync(seeds, programId)[0];
|
|
46821
46997
|
}
|
|
46822
46998
|
function nonce() {
|
|
46823
46999
|
return new anchor8.BN(randomBytes3(8), "le");
|
|
@@ -46830,6 +47006,8 @@ class DepthClient {
|
|
|
46830
47006
|
options;
|
|
46831
47007
|
program;
|
|
46832
47008
|
provider;
|
|
47009
|
+
views;
|
|
47010
|
+
viewReads = new Map;
|
|
46833
47011
|
position;
|
|
46834
47012
|
marketAddress = marketAddress7();
|
|
46835
47013
|
protocolAddress = protocolAddress4();
|
|
@@ -46838,7 +47016,7 @@ class DepthClient {
|
|
|
46838
47016
|
return new MarketCatalog(this);
|
|
46839
47017
|
}
|
|
46840
47018
|
get funding() {
|
|
46841
|
-
return new FundingClient(this.program, this.options.connection, this.options.wallet.publicKey, (name2, offset2) => this.queue(name2, offset2));
|
|
47019
|
+
return new FundingClient(this.program, this.options.connection, this.options.wallet.publicKey, (name2, offset2) => this.queue(name2, offset2), this.options.settlement ?? (this.options.environment && this.options.environment !== "localnet" ? "keeper" : "wallet"));
|
|
46842
47020
|
}
|
|
46843
47021
|
get app() {
|
|
46844
47022
|
return new AppAdmin(this.program, this.options.connection, this.options.wallet.publicKey, this.funding);
|
|
@@ -46852,6 +47030,7 @@ class DepthClient {
|
|
|
46852
47030
|
}
|
|
46853
47031
|
constructor(options) {
|
|
46854
47032
|
this.options = options;
|
|
47033
|
+
this.views = new ViewCache(`${"manifest" in options.deployment ? options.deployment.manifest.payload.genesisHash : "localnet"}:${DEPTH_PROGRAM_ID7.toBase58()}:${options.wallet.publicKey.toBase58()}`, options.privateViews === "device" && "manifest" in options.deployment && typeof indexedDB !== "undefined" && globalThis.crypto?.subtle ? new DeviceViews : undefined);
|
|
46855
47034
|
this.provider = new DepthProvider(options.connection, options.wallet, {
|
|
46856
47035
|
commitment: "confirmed",
|
|
46857
47036
|
preflightCommitment: "confirmed"
|
|
@@ -46860,7 +47039,7 @@ class DepthClient {
|
|
|
46860
47039
|
this.position = this.positionActions();
|
|
46861
47040
|
}
|
|
46862
47041
|
static async create(options) {
|
|
46863
|
-
const appId = typeof options.appId === "string" ? new
|
|
47042
|
+
const appId = typeof options.appId === "string" ? new PublicKey10(options.appId) : options.appId;
|
|
46864
47043
|
const resolved = {
|
|
46865
47044
|
...options,
|
|
46866
47045
|
...await resolveConnection(options),
|
|
@@ -47078,7 +47257,7 @@ class DepthClient {
|
|
|
47078
47257
|
return this.funding.release(amount, clientNonce ?? BigInt(nonce().toString()));
|
|
47079
47258
|
}
|
|
47080
47259
|
async depositRequest(sourceOrAmount, amount, clientNonce) {
|
|
47081
|
-
if (sourceOrAmount instanceof
|
|
47260
|
+
if (sourceOrAmount instanceof PublicKey10) {
|
|
47082
47261
|
if (amount === undefined || clientNonce === undefined)
|
|
47083
47262
|
throw new RangeError("Source deposits require amount and client nonce");
|
|
47084
47263
|
return this.funding.deposit(sourceOrAmount, amount, clientNonce);
|
|
@@ -47089,7 +47268,7 @@ class DepthClient {
|
|
|
47089
47268
|
return this.funding.deposit(source, sourceOrAmount, amount ?? BigInt(nonce().toString()));
|
|
47090
47269
|
}
|
|
47091
47270
|
async withdrawRequest(destinationOrAmount, amount, clientNonce) {
|
|
47092
|
-
if (destinationOrAmount instanceof
|
|
47271
|
+
if (destinationOrAmount instanceof PublicKey10) {
|
|
47093
47272
|
if (amount === undefined || clientNonce === undefined)
|
|
47094
47273
|
throw new RangeError("Destination withdrawals require amount and client nonce");
|
|
47095
47274
|
return this.funding.withdraw(destinationOrAmount, amount, clientNonce);
|
|
@@ -47124,11 +47303,7 @@ class DepthClient {
|
|
|
47124
47303
|
const state = await actions.state();
|
|
47125
47304
|
if (state.status === "uninitialized")
|
|
47126
47305
|
return { ...state, status: "uninitialized", amount: 0n };
|
|
47127
|
-
|
|
47128
|
-
const result = await view.wait(options);
|
|
47129
|
-
if (result.status !== "pending")
|
|
47130
|
-
await view.close();
|
|
47131
|
-
return result;
|
|
47306
|
+
return this.summaryView("balance", state.id, options);
|
|
47132
47307
|
}
|
|
47133
47308
|
};
|
|
47134
47309
|
return Object.assign(() => actions, actions);
|
|
@@ -47164,29 +47339,7 @@ class DepthClient {
|
|
|
47164
47339
|
summary: async (options = {
|
|
47165
47340
|
timeoutMs: 180000
|
|
47166
47341
|
}) => {
|
|
47167
|
-
|
|
47168
|
-
let view;
|
|
47169
|
-
for (;; ) {
|
|
47170
|
-
try {
|
|
47171
|
-
view = await this.requestMarketView();
|
|
47172
|
-
break;
|
|
47173
|
-
} catch (error) {
|
|
47174
|
-
const code2 = error.error?.errorCode?.code;
|
|
47175
|
-
if (code2 !== "WrongMarketAccountStatus" && !String(error).includes("Market account is processing another operation")) {
|
|
47176
|
-
throw error;
|
|
47177
|
-
}
|
|
47178
|
-
if (Date.now() >= deadline)
|
|
47179
|
-
throw error;
|
|
47180
|
-
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
47181
|
-
}
|
|
47182
|
-
}
|
|
47183
|
-
const result = await view.wait({
|
|
47184
|
-
...options,
|
|
47185
|
-
timeoutMs: Math.max(0, deadline - Date.now())
|
|
47186
|
-
});
|
|
47187
|
-
if (result.status !== "pending")
|
|
47188
|
-
await view.close();
|
|
47189
|
-
return result;
|
|
47342
|
+
return this.summaryView("market", address2.toBase58(), options);
|
|
47190
47343
|
}
|
|
47191
47344
|
};
|
|
47192
47345
|
return Object.assign((positionId) => this.positionActions(positionId), actions);
|
|
@@ -47232,6 +47385,75 @@ class DepthClient {
|
|
|
47232
47385
|
u64(clientNonce, "clientNonce").toArrayLike(Buffer2, "le", 8)
|
|
47233
47386
|
]);
|
|
47234
47387
|
}
|
|
47388
|
+
async deferViewClose(kind, id) {
|
|
47389
|
+
const view = new PublicKey10(id);
|
|
47390
|
+
const method = kind === "balance" ? this.program.methods.closeBalanceView : this.program.methods.closeMarketView;
|
|
47391
|
+
this.provider.deferClose(view, await method().accountsPartial({
|
|
47392
|
+
owner: this.options.wallet.publicKey,
|
|
47393
|
+
view
|
|
47394
|
+
}).instruction());
|
|
47395
|
+
}
|
|
47396
|
+
async viewState(kind, id) {
|
|
47397
|
+
if (kind === "balance")
|
|
47398
|
+
return this.account().state();
|
|
47399
|
+
const state = await this.read("MarketAccount", new PublicKey10(id));
|
|
47400
|
+
if (!state.owner.equals(this.options.wallet.publicKey) || !state.market.equals(this.marketAddress))
|
|
47401
|
+
throw new Error("Position does not belong to this wallet and market");
|
|
47402
|
+
return {
|
|
47403
|
+
status: enumName2(state.status),
|
|
47404
|
+
version: BigInt(state.version.toString())
|
|
47405
|
+
};
|
|
47406
|
+
}
|
|
47407
|
+
summaryView(kind, id, options) {
|
|
47408
|
+
const key = `${kind}:${id}`;
|
|
47409
|
+
const pending = this.viewReads.get(key);
|
|
47410
|
+
if (pending)
|
|
47411
|
+
return pending;
|
|
47412
|
+
const request = this.readSummaryView(kind, id, options).finally(() => {
|
|
47413
|
+
if (this.viewReads.get(key) === request)
|
|
47414
|
+
this.viewReads.delete(key);
|
|
47415
|
+
});
|
|
47416
|
+
this.viewReads.set(key, request);
|
|
47417
|
+
return request;
|
|
47418
|
+
}
|
|
47419
|
+
async readSummaryView(kind, id, options) {
|
|
47420
|
+
if (!Number.isSafeInteger(options.timeoutMs) || options.timeoutMs < 0)
|
|
47421
|
+
throw new RangeError("timeoutMs must be a nonnegative integer");
|
|
47422
|
+
const deadline = Date.now() + options.timeoutMs;
|
|
47423
|
+
for (;; ) {
|
|
47424
|
+
const state = await this.viewState(kind, id);
|
|
47425
|
+
if (state.status === "ready") {
|
|
47426
|
+
const cached = await this.views.get(kind, id, state.version);
|
|
47427
|
+
if (cached) {
|
|
47428
|
+
await this.deferViewClose(kind, cached.id);
|
|
47429
|
+
return cached;
|
|
47430
|
+
}
|
|
47431
|
+
try {
|
|
47432
|
+
const view = kind === "balance" ? await this.requestBalanceView() : await this.requestMarketView();
|
|
47433
|
+
const result = await view.wait({
|
|
47434
|
+
...options,
|
|
47435
|
+
timeoutMs: Math.max(0, deadline - Date.now())
|
|
47436
|
+
});
|
|
47437
|
+
if (result.status === "pending")
|
|
47438
|
+
return result;
|
|
47439
|
+
await this.deferViewClose(kind, result.id);
|
|
47440
|
+
const latest = await this.viewState(kind, id);
|
|
47441
|
+
if (result.status === "ready" && latest.status === "ready" && latest.version === result.version) {
|
|
47442
|
+
const snapshot = { ...result, readAt: Date.now() };
|
|
47443
|
+
await this.views.set(kind, id, snapshot);
|
|
47444
|
+
return snapshot;
|
|
47445
|
+
}
|
|
47446
|
+
} catch (error) {
|
|
47447
|
+
const code2 = error.error?.errorCode?.code;
|
|
47448
|
+
if (code2 !== "WrongMarketAccountStatus" && !String(error).includes("processing another operation"))
|
|
47449
|
+
throw error;
|
|
47450
|
+
}
|
|
47451
|
+
}
|
|
47452
|
+
if (Date.now() >= deadline)
|
|
47453
|
+
throw new Error("Private account is still processing an operation");
|
|
47454
|
+
await new Promise((resolve) => setTimeout(resolve, Math.min(options.pollMs ?? 1000, deadline - Date.now())));
|
|
47455
|
+
}
|
|
47456
|
+
}
|
|
47235
47457
|
async submitTrade(input, intent) {
|
|
47236
47458
|
const appId = this.options.appId;
|
|
47237
47459
|
if (!appId)
|
|
@@ -47263,43 +47485,13 @@ class DepthClient {
|
|
|
47263
47485
|
throw new Error("Position does not belong to this wallet and market");
|
|
47264
47486
|
await this.ensureBalanceReady();
|
|
47265
47487
|
await this.ensureMarketReady();
|
|
47266
|
-
let [market, protocol, account, app] = await
|
|
47267
|
-
|
|
47268
|
-
this.read("Protocol", this.protocolAddress),
|
|
47269
|
-
this.read("MarketAccount", this.accountAddress()),
|
|
47270
|
-
this.read("AppConfig", appAddress2(appId))
|
|
47271
|
-
]);
|
|
47272
|
-
const deadline = tradeDeadline(input, Math.floor(Date.now() / 1000), market.state.config.maxOrderQueueSeconds);
|
|
47488
|
+
let [market, protocol, account, app] = await this.waitForMarket(input, appId, intent);
|
|
47489
|
+
let deadline;
|
|
47273
47490
|
tradeLimit(input, "long", BigInt(market.state.oraclePriceE8.toString()));
|
|
47274
|
-
this.validateTrade(market.state, protocol, account, app, appId, intent, deadline);
|
|
47275
47491
|
if (additionalMargin > 0n) {
|
|
47276
47492
|
const transfer = await this.funding.allocate(additionalMargin, clientNonce);
|
|
47277
|
-
|
|
47278
|
-
|
|
47279
|
-
const current = await transfer.status();
|
|
47280
|
-
if (current.state === "settled")
|
|
47281
|
-
break;
|
|
47282
|
-
if (current.state === "rejected" || current.state === "refunded")
|
|
47283
|
-
throw new Error(`Margin allocation ${transfer.id.toBase58()} ${current.state}`);
|
|
47284
|
-
if (current.state === "escrow") {
|
|
47285
|
-
try {
|
|
47286
|
-
await transfer.settle();
|
|
47287
|
-
} catch (error) {
|
|
47288
|
-
if ((await transfer.status()).state === "escrow")
|
|
47289
|
-
throw error;
|
|
47290
|
-
}
|
|
47291
|
-
}
|
|
47292
|
-
if (Date.now() >= allocationDeadline)
|
|
47293
|
-
throw new Error(`Margin allocation ${transfer.id.toBase58()} is pending`);
|
|
47294
|
-
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
47295
|
-
}
|
|
47296
|
-
[market, protocol, account, app] = await Promise.all([
|
|
47297
|
-
this.market(),
|
|
47298
|
-
this.read("Protocol", this.protocolAddress),
|
|
47299
|
-
this.read("MarketAccount", this.accountAddress()),
|
|
47300
|
-
this.read("AppConfig", appAddress2(appId))
|
|
47301
|
-
]);
|
|
47302
|
-
this.validateTrade(market.state, protocol, account, app, appId, intent, deadline);
|
|
47493
|
+
await transfer.confirm({ timeoutMs: 120000 });
|
|
47494
|
+
[market, protocol, account, app] = await this.waitForMarket(input, appId, intent);
|
|
47303
47495
|
}
|
|
47304
47496
|
const viewDeadline = Date.now() + 120000;
|
|
47305
47497
|
let position;
|
|
@@ -47317,15 +47509,13 @@ class DepthClient {
|
|
|
47317
47509
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
47318
47510
|
continue;
|
|
47319
47511
|
}
|
|
47320
|
-
[market, account] = await
|
|
47321
|
-
this.market(),
|
|
47322
|
-
this.read("MarketAccount", this.accountAddress())
|
|
47323
|
-
]);
|
|
47512
|
+
[market, protocol, account, app] = await this.waitForMarket(input, appId, intent);
|
|
47324
47513
|
if (position.status === "ready" && enumName2(account.status) === "ready" && account.version.toString() === position.version.toString()) {
|
|
47325
47514
|
break;
|
|
47326
47515
|
}
|
|
47327
47516
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
47328
47517
|
}
|
|
47518
|
+
deadline = tradeDeadline(input, Math.floor(Date.now() / 1000), market.state.config.maxOrderQueueSeconds);
|
|
47329
47519
|
this.validateTrade(market.state, protocol, account, app, appId, intent, deadline);
|
|
47330
47520
|
if (position.status !== "ready" || position.collateral === undefined || position.position === undefined)
|
|
47331
47521
|
throw new Error(`Private position view ${position.id} is ${position.status}`);
|
|
@@ -47395,6 +47585,29 @@ class DepthClient {
|
|
|
47395
47585
|
]).rpc({ commitment: "confirmed" }).catch((error) => submissionError(order.toBase58(), error));
|
|
47396
47586
|
return new DepthOperation(order, signature, this.program, this.options.connection, (id) => this.requestFillView(id), position);
|
|
47397
47587
|
}
|
|
47588
|
+
async waitForMarket(input, appId, intent) {
|
|
47589
|
+
const until = Date.now() + 60000;
|
|
47590
|
+
for (;; ) {
|
|
47591
|
+
const [market, protocol, account, app] = await Promise.all([
|
|
47592
|
+
this.market(),
|
|
47593
|
+
this.read("Protocol", this.protocolAddress),
|
|
47594
|
+
this.read("MarketAccount", this.accountAddress()),
|
|
47595
|
+
this.read("AppConfig", appAddress2(appId))
|
|
47596
|
+
]);
|
|
47597
|
+
const deadline = tradeDeadline(input, Math.floor(Date.now() / 1000), market.state.config.maxOrderQueueSeconds);
|
|
47598
|
+
try {
|
|
47599
|
+
this.validateTrade(market.state, protocol, account, app, appId, intent, deadline);
|
|
47600
|
+
return [market, protocol, account, app];
|
|
47601
|
+
} catch (error) {
|
|
47602
|
+
if (!(error instanceof Error) || ![
|
|
47603
|
+
"Waiting for maker liquidity",
|
|
47604
|
+
"Market is processing another order"
|
|
47605
|
+
].includes(error.message) || Date.now() >= until)
|
|
47606
|
+
throw error;
|
|
47607
|
+
}
|
|
47608
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
47609
|
+
}
|
|
47610
|
+
}
|
|
47398
47611
|
validateTrade(market, protocol, account, app, appId, intent = "increase", deadline) {
|
|
47399
47612
|
const now = Math.floor(Date.now() / 1000);
|
|
47400
47613
|
const marketStatus = enumName2(market.status);
|
|
@@ -47407,9 +47620,10 @@ class DepthClient {
|
|
|
47407
47620
|
if (enumName2(account.status) !== "ready" || !account.market.equals(this.marketAddress) || !account.owner.equals(this.options.wallet.publicKey)) {
|
|
47408
47621
|
throw new Error("Market account is unavailable");
|
|
47409
47622
|
}
|
|
47410
|
-
if (market.pendingOrders !== 0
|
|
47411
|
-
throw new Error("Market is processing another order
|
|
47412
|
-
|
|
47623
|
+
if (market.pendingOrders !== 0)
|
|
47624
|
+
throw new Error("Market is processing another order");
|
|
47625
|
+
if (market.activeQuoteCount === 0)
|
|
47626
|
+
throw new Error("Waiting for maker liquidity");
|
|
47413
47627
|
const age = now - market.oracleTimestamp.toNumber();
|
|
47414
47628
|
if (age < 0 || age > market.config.maxOracleAgeSeconds) {
|
|
47415
47629
|
throw new Error("Oracle update is stale");
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { BalanceSnapshot, PositionSnapshot } from "./view.js";
|
|
2
|
+
type Snapshot = BalanceSnapshot | PositionSnapshot;
|
|
3
|
+
type Kind = "balance" | "market";
|
|
4
|
+
type Envelope = {
|
|
5
|
+
iv: Uint8Array;
|
|
6
|
+
data: ArrayBuffer;
|
|
7
|
+
};
|
|
8
|
+
export interface ViewStorage {
|
|
9
|
+
key(scope: string, proposed: CryptoKey): Promise<CryptoKey>;
|
|
10
|
+
read(id: string): Promise<Envelope | undefined>;
|
|
11
|
+
write(id: string, value: Envelope): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
export declare class DeviceViews implements ViewStorage {
|
|
14
|
+
private database?;
|
|
15
|
+
private open;
|
|
16
|
+
key(scope: string, proposed: CryptoKey): Promise<CryptoKey>;
|
|
17
|
+
read(id: string): Promise<Envelope | undefined>;
|
|
18
|
+
write(id: string, value: Envelope): Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
export declare class ViewCache {
|
|
21
|
+
private readonly scope;
|
|
22
|
+
private readonly storage?;
|
|
23
|
+
private readonly memory;
|
|
24
|
+
private key?;
|
|
25
|
+
constructor(scope: string, storage?: ViewStorage | undefined);
|
|
26
|
+
private encryptionKey;
|
|
27
|
+
private id;
|
|
28
|
+
get<T extends Snapshot>(kind: Kind, account: string, version: bigint): Promise<T | undefined>;
|
|
29
|
+
set(kind: Kind, account: string, snapshot: Snapshot): Promise<void>;
|
|
30
|
+
}
|
|
31
|
+
export {};
|
package/dist/view/view.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export type BalanceSnapshot = {
|
|
|
4
4
|
status: "uninitialized" | "pending" | "ready" | "stale";
|
|
5
5
|
id: string;
|
|
6
6
|
version: bigint;
|
|
7
|
+
readAt?: number;
|
|
7
8
|
slot: number;
|
|
8
9
|
amount?: bigint;
|
|
9
10
|
};
|
|
@@ -11,6 +12,7 @@ export type PositionSnapshot = {
|
|
|
11
12
|
status: "pending" | "ready" | "stale";
|
|
12
13
|
id: string;
|
|
13
14
|
version: bigint;
|
|
15
|
+
readAt?: number;
|
|
14
16
|
slot: number;
|
|
15
17
|
collateral?: bigint;
|
|
16
18
|
reserved?: bigint;
|
|
@@ -55,5 +57,7 @@ export declare class DepthView {
|
|
|
55
57
|
timeoutMs: number;
|
|
56
58
|
pollMs?: number;
|
|
57
59
|
}): Promise<BalanceSnapshot | PositionSnapshot | FillSnapshot | QuoteBalanceSnapshot>;
|
|
60
|
+
deferClose(): Promise<void>;
|
|
61
|
+
private closeBuilder;
|
|
58
62
|
close(): Promise<string>;
|
|
59
63
|
}
|
package/dist/view/view.js
CHANGED
|
@@ -26667,13 +26667,28 @@ class DepthView {
|
|
|
26667
26667
|
await new Promise((resolve) => setTimeout(resolve, Math.min(pollMs, deadline - Date.now())));
|
|
26668
26668
|
}
|
|
26669
26669
|
}
|
|
26670
|
+
async deferClose() {
|
|
26671
|
+
const provider = this.program.provider;
|
|
26672
|
+
if (typeof provider.deferClose !== "function") {
|
|
26673
|
+
await this.close();
|
|
26674
|
+
return;
|
|
26675
|
+
}
|
|
26676
|
+
const snapshot = await this.status();
|
|
26677
|
+
if (snapshot.status === "pending")
|
|
26678
|
+
throw new Error("Private view computation is still pending");
|
|
26679
|
+
const instruction = await this.closeBuilder().instruction();
|
|
26680
|
+
provider.deferClose(this.id, instruction);
|
|
26681
|
+
}
|
|
26682
|
+
closeBuilder() {
|
|
26683
|
+
const builder = this.kind === "balance" ? this.program.methods.closeBalanceView() : this.kind === "market" ? this.program.methods.closeMarketView() : this.kind === "fill" ? this.program.methods.closeFillView() : this.program.methods.closeQuoteView();
|
|
26684
|
+
return builder.accountsPartial({ owner: this.owner, view: this.id });
|
|
26685
|
+
}
|
|
26670
26686
|
async close() {
|
|
26671
26687
|
const snapshot = await this.status();
|
|
26672
26688
|
if (snapshot.status === "pending") {
|
|
26673
26689
|
throw new Error("Private view computation is still pending");
|
|
26674
26690
|
}
|
|
26675
|
-
|
|
26676
|
-
return builder.accountsPartial({ owner: this.owner, view: this.id }).rpc({ commitment: "confirmed" });
|
|
26691
|
+
return this.closeBuilder().rpc({ commitment: "confirmed" });
|
|
26677
26692
|
}
|
|
26678
26693
|
}
|
|
26679
26694
|
export {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@depthhq/sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -47,6 +47,9 @@
|
|
|
47
47
|
"@depthhq/bindings": "0.1.1",
|
|
48
48
|
"@depthhq/schema": "0.1.1"
|
|
49
49
|
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"fake-indexeddb": "6.2.4"
|
|
52
|
+
},
|
|
50
53
|
"scripts": {
|
|
51
54
|
"build": "node ../../scripts/build-package.mjs sdk",
|
|
52
55
|
"typecheck": "tsc --noEmit",
|