@depthhq/sdk 0.1.2 → 0.1.4
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 +12 -1
- package/dist/client/types.d.ts +6 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +617 -127
- package/dist/view/cache.d.ts +40 -0
- package/dist/view/session.d.ts +28 -0
- package/dist/view/view.d.ts +7 -1
- package/dist/view/view.js +31 -3
- package/package.json +6 -3
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 anchor9 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;
|
|
@@ -43622,13 +43622,13 @@ import {
|
|
|
43622
43622
|
circuits as circuits2,
|
|
43623
43623
|
computationName,
|
|
43624
43624
|
DEPTH_IDL as DEPTH_IDL3,
|
|
43625
|
-
DEPTH_PROGRAM_ID as
|
|
43626
|
-
marketAddress as
|
|
43625
|
+
DEPTH_PROGRAM_ID as DEPTH_PROGRAM_ID8,
|
|
43626
|
+
marketAddress as marketAddress8,
|
|
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 PublicKey11 } from "@solana/web3.js";
|
|
43632
43632
|
|
|
43633
43633
|
// src/chain/random.ts
|
|
43634
43634
|
function randomBytes3(length) {
|
|
@@ -44335,9 +44335,21 @@ async function getExtendedPublicKey(key) {
|
|
|
44335
44335
|
function getExtendedPublicKeySync(key) {
|
|
44336
44336
|
return getKeyFromHash(sha512s(checkPrivateKey(key)));
|
|
44337
44337
|
}
|
|
44338
|
+
async function getPublicKey(privateKey) {
|
|
44339
|
+
return (await getExtendedPublicKey(privateKey)).pointBytes;
|
|
44340
|
+
}
|
|
44338
44341
|
function getPublicKeySync(privateKey) {
|
|
44339
44342
|
return getExtendedPublicKeySync(privateKey).pointBytes;
|
|
44340
44343
|
}
|
|
44344
|
+
async function sign(message, privateKey) {
|
|
44345
|
+
message = ensureBytes2(message);
|
|
44346
|
+
const { prefix, scalar, pointBytes } = await getExtendedPublicKey(privateKey);
|
|
44347
|
+
const r = modlLE(await utils.sha512(prefix, message));
|
|
44348
|
+
const R = Point.BASE.multiply(r);
|
|
44349
|
+
const k = modlLE(await utils.sha512(R.toRawBytes(), pointBytes, message));
|
|
44350
|
+
const s = mod2(r + k * scalar, CURVE.l);
|
|
44351
|
+
return new Signature(R, s).toRawBytes();
|
|
44352
|
+
}
|
|
44341
44353
|
function signSync(message, privateKey) {
|
|
44342
44354
|
message = ensureBytes2(message);
|
|
44343
44355
|
const { prefix, scalar, pointBytes } = getExtendedPublicKeySync(privateKey);
|
|
@@ -44726,6 +44738,7 @@ import { DEPTH_IDL as DEPTH_IDL2, DEPTH_PROGRAM_ID as DEPTH_PROGRAM_ID3 } from "
|
|
|
44726
44738
|
import {
|
|
44727
44739
|
ComputeBudgetProgram,
|
|
44728
44740
|
SendTransactionError,
|
|
44741
|
+
PublicKey as PublicKey4,
|
|
44729
44742
|
Transaction
|
|
44730
44743
|
} from "@solana/web3.js";
|
|
44731
44744
|
var queuedInstructions = new Set([
|
|
@@ -44768,11 +44781,52 @@ function applyDepthComputeBudget(transaction) {
|
|
|
44768
44781
|
}
|
|
44769
44782
|
|
|
44770
44783
|
class DepthProvider extends anchor3.AnchorProvider {
|
|
44784
|
+
cleanup = new Map;
|
|
44785
|
+
deferClose(id, instruction) {
|
|
44786
|
+
this.cleanup.set(id.toBase58(), instruction);
|
|
44787
|
+
}
|
|
44788
|
+
async appendCleanup(transaction) {
|
|
44789
|
+
if (!this.cleanup.size || transaction.signatures.some((item) => item.signature))
|
|
44790
|
+
return [];
|
|
44791
|
+
const entries = [...this.cleanup.entries()].slice(0, 64);
|
|
44792
|
+
const queued = new Set(entries.map(([, instruction]) => instruction));
|
|
44793
|
+
transaction.instructions = transaction.instructions.filter((instruction) => !queued.has(instruction));
|
|
44794
|
+
const accounts2 = await this.connection.getMultipleAccountsInfo(entries.map(([id]) => new PublicKey4(id)), "confirmed");
|
|
44795
|
+
const added = [];
|
|
44796
|
+
for (let index = 0;index < entries.length; index++) {
|
|
44797
|
+
const [id, instruction] = entries[index];
|
|
44798
|
+
if (!accounts2[index]?.owner.equals(DEPTH_PROGRAM_ID3)) {
|
|
44799
|
+
this.cleanup.delete(id);
|
|
44800
|
+
continue;
|
|
44801
|
+
}
|
|
44802
|
+
const candidate = new Transaction({
|
|
44803
|
+
feePayer: transaction.feePayer ?? this.wallet.publicKey,
|
|
44804
|
+
recentBlockhash: transaction.recentBlockhash ?? PublicKey4.default.toBase58()
|
|
44805
|
+
}).add(...transaction.instructions, instruction);
|
|
44806
|
+
try {
|
|
44807
|
+
candidate.serialize({
|
|
44808
|
+
requireAllSignatures: false,
|
|
44809
|
+
verifySignatures: false
|
|
44810
|
+
});
|
|
44811
|
+
} catch {
|
|
44812
|
+
continue;
|
|
44813
|
+
}
|
|
44814
|
+
transaction.add(instruction);
|
|
44815
|
+
added.push(id);
|
|
44816
|
+
}
|
|
44817
|
+
return added;
|
|
44818
|
+
}
|
|
44771
44819
|
async sendAndConfirm(transaction, signers, options) {
|
|
44772
|
-
|
|
44820
|
+
let cleanup = [];
|
|
44821
|
+
if (transaction instanceof Transaction) {
|
|
44773
44822
|
applyDepthComputeBudget(transaction);
|
|
44823
|
+
cleanup = await this.appendCleanup(transaction);
|
|
44824
|
+
}
|
|
44774
44825
|
try {
|
|
44775
|
-
|
|
44826
|
+
const signature = await super.sendAndConfirm(transaction, signers, options);
|
|
44827
|
+
for (const id of cleanup)
|
|
44828
|
+
this.cleanup.delete(id);
|
|
44829
|
+
return signature;
|
|
44776
44830
|
} catch (error) {
|
|
44777
44831
|
if (!(error instanceof Error) || !error.message.includes("Unknown action 'undefined'"))
|
|
44778
44832
|
throw error;
|
|
@@ -45023,7 +45077,7 @@ import {
|
|
|
45023
45077
|
transferAddress,
|
|
45024
45078
|
withdrawalAddress
|
|
45025
45079
|
} from "@depthhq/bindings";
|
|
45026
|
-
import { PublicKey as
|
|
45080
|
+
import { PublicKey as PublicKey5 } from "@solana/web3.js";
|
|
45027
45081
|
|
|
45028
45082
|
// src/chain/transaction.ts
|
|
45029
45083
|
init_buffer();
|
|
@@ -45181,7 +45235,7 @@ class FundingDiscovery {
|
|
|
45181
45235
|
const limit = options.limit ?? 20;
|
|
45182
45236
|
if (!Number.isSafeInteger(limit) || limit < 1 || limit > 100)
|
|
45183
45237
|
throw new RangeError("limit must be an integer from 1 to 100");
|
|
45184
|
-
const cursor = options.cursor ? new
|
|
45238
|
+
const cursor = options.cursor ? new PublicKey5(options.cursor).toBase58() : undefined;
|
|
45185
45239
|
const accounts2 = await this.connection.getProgramAccounts(this.program.programId, {
|
|
45186
45240
|
commitment: "confirmed",
|
|
45187
45241
|
dataSlice: { offset: 0, length: 0 },
|
|
@@ -45213,7 +45267,7 @@ class FundingDiscovery {
|
|
|
45213
45267
|
const current = status(state);
|
|
45214
45268
|
if (!state.toMarket || current !== "settled")
|
|
45215
45269
|
return;
|
|
45216
|
-
const orderId =
|
|
45270
|
+
const orderId = PublicKey5.findProgramAddressSync([
|
|
45217
45271
|
Buffer2.from("order"),
|
|
45218
45272
|
state.market.toBuffer(),
|
|
45219
45273
|
this.owner.toBuffer(),
|
|
@@ -45260,7 +45314,7 @@ class FundingDiscovery {
|
|
|
45260
45314
|
const limit = options.limit ?? 20;
|
|
45261
45315
|
if (!Number.isSafeInteger(limit) || limit < 1 || limit > 100)
|
|
45262
45316
|
throw new RangeError("limit must be an integer from 1 to 100");
|
|
45263
|
-
const cursor = options.cursor ? new
|
|
45317
|
+
const cursor = options.cursor ? new PublicKey5(options.cursor).toBase58() : undefined;
|
|
45264
45318
|
const types3 = [
|
|
45265
45319
|
{
|
|
45266
45320
|
name: "depositReceipt",
|
|
@@ -45351,7 +45405,7 @@ class FundingDiscovery {
|
|
|
45351
45405
|
throw new Error("Order changed during discovery");
|
|
45352
45406
|
const bytes = Buffer2.alloc(8);
|
|
45353
45407
|
bytes.writeBigUInt64LE(nonce);
|
|
45354
|
-
canonical =
|
|
45408
|
+
canonical = PublicKey5.findProgramAddressSync([
|
|
45355
45409
|
Buffer2.from("order"),
|
|
45356
45410
|
state.market.toBuffer(),
|
|
45357
45411
|
this.owner.toBuffer(),
|
|
@@ -45437,15 +45491,17 @@ class FundingClient {
|
|
|
45437
45491
|
connection;
|
|
45438
45492
|
owner;
|
|
45439
45493
|
queue;
|
|
45494
|
+
settlement;
|
|
45440
45495
|
market;
|
|
45441
45496
|
protocol;
|
|
45442
45497
|
balance;
|
|
45443
45498
|
marketAccount;
|
|
45444
|
-
constructor(program, connection, owner, queue) {
|
|
45499
|
+
constructor(program, connection, owner, queue, settlement = "wallet") {
|
|
45445
45500
|
this.program = program;
|
|
45446
45501
|
this.connection = connection;
|
|
45447
45502
|
this.owner = owner;
|
|
45448
45503
|
this.queue = queue;
|
|
45504
|
+
this.settlement = settlement;
|
|
45449
45505
|
this.market = marketAddress3(program.programId);
|
|
45450
45506
|
this.protocol = protocolAddress2(program.programId);
|
|
45451
45507
|
this.balance = balanceAddress(owner, program.programId);
|
|
@@ -45779,7 +45835,7 @@ class TransferHandle {
|
|
|
45779
45835
|
return true;
|
|
45780
45836
|
if (transfer.state === "rejected" || transfer.state === "refunded" || transfer.state === "cancelled")
|
|
45781
45837
|
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") {
|
|
45838
|
+
if (transfer.state === "escrow" && this.client.settlement === "wallet") {
|
|
45783
45839
|
try {
|
|
45784
45840
|
await this.settle();
|
|
45785
45841
|
} catch (error) {
|
|
@@ -45883,15 +45939,15 @@ async function balanceState(program, connection, owner, address2) {
|
|
|
45883
45939
|
// src/account/token.ts
|
|
45884
45940
|
init_buffer();
|
|
45885
45941
|
import {
|
|
45886
|
-
PublicKey as
|
|
45942
|
+
PublicKey as PublicKey6,
|
|
45887
45943
|
SystemProgram,
|
|
45888
45944
|
Transaction as Transaction2,
|
|
45889
|
-
TransactionInstruction
|
|
45945
|
+
TransactionInstruction as TransactionInstruction2
|
|
45890
45946
|
} from "@solana/web3.js";
|
|
45891
|
-
var tokenProgram = new
|
|
45892
|
-
var associatedProgram = new
|
|
45947
|
+
var tokenProgram = new PublicKey6("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
|
|
45948
|
+
var associatedProgram = new PublicKey6("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL");
|
|
45893
45949
|
function associatedTokenAddress(owner, mint) {
|
|
45894
|
-
return
|
|
45950
|
+
return PublicKey6.findProgramAddressSync([owner.toBuffer(), tokenProgram.toBuffer(), mint.toBuffer()], associatedProgram)[0];
|
|
45895
45951
|
}
|
|
45896
45952
|
function tokenBalance(info, owner, mint) {
|
|
45897
45953
|
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 +45976,7 @@ async function destinationTokenAccount(provider, owner, mint) {
|
|
|
45920
45976
|
const address2 = associatedTokenAddress(owner, mint);
|
|
45921
45977
|
let info = await provider.connection.getAccountInfo(address2, "confirmed");
|
|
45922
45978
|
if (!info) {
|
|
45923
|
-
const instruction = new
|
|
45979
|
+
const instruction = new TransactionInstruction2({
|
|
45924
45980
|
programId: associatedProgram,
|
|
45925
45981
|
data: Buffer2.from([1]),
|
|
45926
45982
|
keys: [
|
|
@@ -45962,7 +46018,7 @@ import {
|
|
|
45962
46018
|
marketAddress as marketAddress4,
|
|
45963
46019
|
SOL_USD_MARKET_ID as SOL_USD_MARKET_ID2
|
|
45964
46020
|
} from "@depthhq/bindings";
|
|
45965
|
-
import { PublicKey as
|
|
46021
|
+
import { PublicKey as PublicKey7 } from "@solana/web3.js";
|
|
45966
46022
|
|
|
45967
46023
|
// src/position/pnl.ts
|
|
45968
46024
|
var scale = 100000000000n;
|
|
@@ -45970,22 +46026,22 @@ function positionPnl(position, priceE8, fundingIndex, fill) {
|
|
|
45970
46026
|
if (position.status !== "ready" || position.position === undefined || position.position === 0n || position.entryPriceE8 === undefined || position.fundingCheckpoint === undefined || position.collateral !== undefined && position.collateral < 0n || priceE8 <= 0n)
|
|
45971
46027
|
throw new Error("A ready open position and a positive price are required");
|
|
45972
46028
|
const size = position.position < 0n ? -position.position : position.position;
|
|
45973
|
-
const
|
|
46029
|
+
const sign2 = position.position > 0n ? 1n : -1n;
|
|
45974
46030
|
let closing = size;
|
|
45975
46031
|
let fee = 0n;
|
|
45976
46032
|
let state = "open";
|
|
45977
46033
|
if (fill) {
|
|
45978
|
-
if (fill.status !== "ready" || fill.side !== -
|
|
46034
|
+
if (fill.status !== "ready" || fill.side !== -sign2 || fill.size === undefined || fill.size <= 0n || fill.executionPriceE8 !== priceE8 || fill.fee === undefined || fill.fee < 0n)
|
|
45979
46035
|
throw new Error("A ready opposite-side execution is required");
|
|
45980
46036
|
closing = fill.size < size ? fill.size : size;
|
|
45981
46037
|
fee = fill.fee;
|
|
45982
46038
|
state = fill.size === size ? "closed" : fill.size < size ? "reduced" : "reversed";
|
|
45983
46039
|
}
|
|
45984
|
-
const gross =
|
|
46040
|
+
const gross = sign2 * closing * (priceE8 - position.entryPriceE8) / scale;
|
|
45985
46041
|
const funding = position.position * (fundingIndex - position.fundingCheckpoint) / scale;
|
|
45986
46042
|
const net = gross - funding - fee;
|
|
45987
46043
|
return {
|
|
45988
|
-
side:
|
|
46044
|
+
side: sign2 > 0n ? "long" : "short",
|
|
45989
46045
|
state,
|
|
45990
46046
|
entryPriceE8: position.entryPriceE8,
|
|
45991
46047
|
priceE8,
|
|
@@ -46192,11 +46248,11 @@ class DepthOperation {
|
|
|
46192
46248
|
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
46249
|
this.fill = {
|
|
46194
46250
|
...result,
|
|
46195
|
-
positionId: marketAccountAddress2(new
|
|
46251
|
+
positionId: marketAccountAddress2(new PublicKey7(snapshot.owner), this.program.programId)
|
|
46196
46252
|
};
|
|
46197
46253
|
}
|
|
46198
46254
|
try {
|
|
46199
|
-
await this.view.
|
|
46255
|
+
await this.view.deferClose();
|
|
46200
46256
|
} catch (error) {
|
|
46201
46257
|
let remaining;
|
|
46202
46258
|
try {
|
|
@@ -46212,7 +46268,7 @@ class DepthOperation {
|
|
|
46212
46268
|
return this.fill;
|
|
46213
46269
|
}
|
|
46214
46270
|
cleanupError(cause) {
|
|
46215
|
-
return new DepthError("FILL_VIEW_CLEANUP_PENDING", "confirmation", "Private fill was read but
|
|
46271
|
+
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
46272
|
}
|
|
46217
46273
|
}
|
|
46218
46274
|
|
|
@@ -46223,22 +46279,22 @@ import {
|
|
|
46223
46279
|
marketAddress as marketAddress5,
|
|
46224
46280
|
protocolAddress as protocolAddress3
|
|
46225
46281
|
} from "@depthhq/bindings";
|
|
46226
|
-
import { PublicKey as
|
|
46282
|
+
import { PublicKey as PublicKey8 } from "@solana/web3.js";
|
|
46227
46283
|
|
|
46228
46284
|
class DepthRecovery {
|
|
46229
46285
|
program;
|
|
46230
46286
|
connection;
|
|
46231
46287
|
owner;
|
|
46232
46288
|
market = marketAddress5();
|
|
46233
|
-
winddown =
|
|
46289
|
+
winddown = PublicKey8.findProgramAddressSync([Buffer2.from("winddown"), this.market.toBuffer()], DEPTH_PROGRAM_ID5)[0];
|
|
46234
46290
|
marketAccount;
|
|
46235
46291
|
claim;
|
|
46236
46292
|
constructor(program, connection, owner) {
|
|
46237
46293
|
this.program = program;
|
|
46238
46294
|
this.connection = connection;
|
|
46239
46295
|
this.owner = owner;
|
|
46240
|
-
this.marketAccount =
|
|
46241
|
-
this.claim =
|
|
46296
|
+
this.marketAccount = PublicKey8.findProgramAddressSync([Buffer2.from("market-account"), this.market.toBuffer(), owner.toBuffer()], DEPTH_PROGRAM_ID5)[0];
|
|
46297
|
+
this.claim = PublicKey8.findProgramAddressSync([Buffer2.from("winddown-claim"), this.marketAccount.toBuffer()], DEPTH_PROGRAM_ID5)[0];
|
|
46242
46298
|
}
|
|
46243
46299
|
async read(address2, name2) {
|
|
46244
46300
|
const result = await this.connection.getAccountInfoAndContext(address2, "confirmed");
|
|
@@ -46328,7 +46384,7 @@ import {
|
|
|
46328
46384
|
marketAddress as marketAddress6,
|
|
46329
46385
|
transferAddress as transferAddress3
|
|
46330
46386
|
} from "@depthhq/bindings";
|
|
46331
|
-
import { PublicKey as
|
|
46387
|
+
import { PublicKey as PublicKey9 } from "@solana/web3.js";
|
|
46332
46388
|
|
|
46333
46389
|
// src/history/replay.ts
|
|
46334
46390
|
function replayFill(state, fill, fundingIndex, maker = false) {
|
|
@@ -46407,7 +46463,7 @@ class ExecutionHistory {
|
|
|
46407
46463
|
this.requestView = requestView;
|
|
46408
46464
|
}
|
|
46409
46465
|
orderAddress(trader, nonce) {
|
|
46410
|
-
return
|
|
46466
|
+
return PublicKey9.findProgramAddressSync([
|
|
46411
46467
|
Buffer2.from("order"),
|
|
46412
46468
|
marketAddress6(this.program.programId).toBuffer(),
|
|
46413
46469
|
trader.toBuffer(),
|
|
@@ -46429,7 +46485,7 @@ class ExecutionHistory {
|
|
|
46429
46485
|
}
|
|
46430
46486
|
const result = this.fills.get(key) ?? await view.wait({ timeoutMs: 180000 });
|
|
46431
46487
|
if (result.status === "stale") {
|
|
46432
|
-
await view.
|
|
46488
|
+
await view.deferClose();
|
|
46433
46489
|
this.views.delete(key);
|
|
46434
46490
|
throw new Error("Historical private execution changed; retry with the same wallet");
|
|
46435
46491
|
}
|
|
@@ -46437,7 +46493,7 @@ class ExecutionHistory {
|
|
|
46437
46493
|
throw new Error("Historical private execution is still pending; retry with the same wallet");
|
|
46438
46494
|
this.fills.set(key, result);
|
|
46439
46495
|
try {
|
|
46440
|
-
await view.
|
|
46496
|
+
await view.deferClose();
|
|
46441
46497
|
} catch (error) {
|
|
46442
46498
|
if (await this.connection.getAccountInfo(view.id, "confirmed"))
|
|
46443
46499
|
throw error;
|
|
@@ -46721,7 +46777,9 @@ class DepthView {
|
|
|
46721
46777
|
mxePublicKey;
|
|
46722
46778
|
program;
|
|
46723
46779
|
connection;
|
|
46724
|
-
|
|
46780
|
+
source;
|
|
46781
|
+
release;
|
|
46782
|
+
constructor(id, signature, kind, owner, secret, publicKey, mxePublicKey, program, connection, source, release) {
|
|
46725
46783
|
this.id = id;
|
|
46726
46784
|
this.signature = signature;
|
|
46727
46785
|
this.kind = kind;
|
|
@@ -46731,6 +46789,8 @@ class DepthView {
|
|
|
46731
46789
|
this.mxePublicKey = mxePublicKey;
|
|
46732
46790
|
this.program = program;
|
|
46733
46791
|
this.connection = connection;
|
|
46792
|
+
this.source = source;
|
|
46793
|
+
this.release = release;
|
|
46734
46794
|
}
|
|
46735
46795
|
async status() {
|
|
46736
46796
|
const response = await this.connection.getAccountInfoAndContext(this.id, "confirmed");
|
|
@@ -46741,6 +46801,9 @@ class DepthView {
|
|
|
46741
46801
|
if (!state.owner.equals(this.owner) || !Buffer2.from(state.viewKey).equals(Buffer2.from(this.publicKey))) {
|
|
46742
46802
|
throw new Error("Private view authorization does not match this request");
|
|
46743
46803
|
}
|
|
46804
|
+
const source = this.kind === "balance" ? state.balance : this.kind === "market" ? state.marketAccount : this.kind === "fill" ? state.order : state.quote;
|
|
46805
|
+
if (this.source && !source?.equals(this.source))
|
|
46806
|
+
throw new Error("Private view source does not match this request");
|
|
46744
46807
|
const current = Object.keys(state.status)[0];
|
|
46745
46808
|
if (current !== "pending" && current !== "ready" && current !== "stale") {
|
|
46746
46809
|
throw new Error("Private view has an unknown status");
|
|
@@ -46805,22 +46868,400 @@ class DepthView {
|
|
|
46805
46868
|
await new Promise((resolve) => setTimeout(resolve, Math.min(pollMs, deadline - Date.now())));
|
|
46806
46869
|
}
|
|
46807
46870
|
}
|
|
46871
|
+
async deferClose() {
|
|
46872
|
+
if (this.release) {
|
|
46873
|
+
await this.close();
|
|
46874
|
+
return;
|
|
46875
|
+
}
|
|
46876
|
+
const provider = this.program.provider;
|
|
46877
|
+
if (typeof provider.deferClose !== "function") {
|
|
46878
|
+
await this.close();
|
|
46879
|
+
return;
|
|
46880
|
+
}
|
|
46881
|
+
const snapshot = await this.status();
|
|
46882
|
+
if (snapshot.status === "pending")
|
|
46883
|
+
throw new Error("Private view computation is still pending");
|
|
46884
|
+
const instruction = await this.closeBuilder().instruction();
|
|
46885
|
+
provider.deferClose(this.id, instruction);
|
|
46886
|
+
}
|
|
46887
|
+
closeBuilder() {
|
|
46888
|
+
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();
|
|
46889
|
+
return builder.accountsPartial({ owner: this.owner, view: this.id });
|
|
46890
|
+
}
|
|
46808
46891
|
async close() {
|
|
46809
46892
|
const snapshot = await this.status();
|
|
46810
46893
|
if (snapshot.status === "pending") {
|
|
46811
46894
|
throw new Error("Private view computation is still pending");
|
|
46812
46895
|
}
|
|
46813
|
-
|
|
46814
|
-
|
|
46896
|
+
if (this.release)
|
|
46897
|
+
return this.release();
|
|
46898
|
+
return this.closeBuilder().rpc({ commitment: "confirmed" });
|
|
46899
|
+
}
|
|
46900
|
+
}
|
|
46901
|
+
|
|
46902
|
+
// src/view/session.ts
|
|
46903
|
+
init_buffer();
|
|
46904
|
+
import * as anchor8 from "@anchor-lang/core";
|
|
46905
|
+
import {
|
|
46906
|
+
DEPTH_PROGRAM_ID as DEPTH_PROGRAM_ID7,
|
|
46907
|
+
marketAddress as marketAddress7,
|
|
46908
|
+
viewPermitAddress
|
|
46909
|
+
} from "@depthhq/bindings";
|
|
46910
|
+
import {
|
|
46911
|
+
viewMessage
|
|
46912
|
+
} from "@depthhq/schema";
|
|
46913
|
+
import { PublicKey as PublicKey10 } from "@solana/web3.js";
|
|
46914
|
+
|
|
46915
|
+
// src/view/cache.ts
|
|
46916
|
+
class DeviceViews {
|
|
46917
|
+
database;
|
|
46918
|
+
open() {
|
|
46919
|
+
return this.database ??= new Promise((resolve, reject) => {
|
|
46920
|
+
const request = indexedDB.open("depth-private-views", 1);
|
|
46921
|
+
request.onupgradeneeded = () => {
|
|
46922
|
+
request.result.createObjectStore("keys");
|
|
46923
|
+
request.result.createObjectStore("views");
|
|
46924
|
+
};
|
|
46925
|
+
request.onerror = () => reject(request.error);
|
|
46926
|
+
request.onblocked = () => reject(new Error("Private view storage is blocked"));
|
|
46927
|
+
request.onsuccess = () => resolve(request.result);
|
|
46928
|
+
});
|
|
46929
|
+
}
|
|
46930
|
+
async key(scope, proposed) {
|
|
46931
|
+
const database = await this.open();
|
|
46932
|
+
return new Promise((resolve, reject) => {
|
|
46933
|
+
const transaction = database.transaction("keys", "readwrite");
|
|
46934
|
+
const store = transaction.objectStore("keys");
|
|
46935
|
+
const request = store.get(scope);
|
|
46936
|
+
let value2;
|
|
46937
|
+
request.onsuccess = () => {
|
|
46938
|
+
value2 = request.result ?? proposed;
|
|
46939
|
+
if (!request.result)
|
|
46940
|
+
store.put(value2, scope);
|
|
46941
|
+
};
|
|
46942
|
+
transaction.oncomplete = () => resolve(value2);
|
|
46943
|
+
transaction.onabort = () => reject(transaction.error);
|
|
46944
|
+
transaction.onerror = () => reject(transaction.error);
|
|
46945
|
+
});
|
|
46946
|
+
}
|
|
46947
|
+
async read(id) {
|
|
46948
|
+
const database = await this.open();
|
|
46949
|
+
return new Promise((resolve, reject) => {
|
|
46950
|
+
const transaction = database.transaction("views", "readonly");
|
|
46951
|
+
const request = transaction.objectStore("views").get(id);
|
|
46952
|
+
transaction.oncomplete = () => resolve(request.result);
|
|
46953
|
+
transaction.onabort = () => reject(transaction.error);
|
|
46954
|
+
transaction.onerror = () => reject(transaction.error);
|
|
46955
|
+
});
|
|
46956
|
+
}
|
|
46957
|
+
async write(id, value2) {
|
|
46958
|
+
const database = await this.open();
|
|
46959
|
+
return new Promise((resolve, reject) => {
|
|
46960
|
+
const transaction = database.transaction("views", "readwrite");
|
|
46961
|
+
transaction.objectStore("views").put(value2, id);
|
|
46962
|
+
transaction.oncomplete = () => resolve();
|
|
46963
|
+
transaction.onabort = () => reject(transaction.error);
|
|
46964
|
+
transaction.onerror = () => reject(transaction.error);
|
|
46965
|
+
});
|
|
46966
|
+
}
|
|
46967
|
+
}
|
|
46968
|
+
|
|
46969
|
+
class EncryptedViews {
|
|
46970
|
+
scope;
|
|
46971
|
+
storage;
|
|
46972
|
+
key;
|
|
46973
|
+
constructor(scope, storage) {
|
|
46974
|
+
this.scope = scope;
|
|
46975
|
+
this.storage = storage;
|
|
46976
|
+
}
|
|
46977
|
+
encryptionKey() {
|
|
46978
|
+
return this.key ??= crypto.subtle.generateKey({ name: "AES-GCM", length: 256 }, false, [
|
|
46979
|
+
"encrypt",
|
|
46980
|
+
"decrypt"
|
|
46981
|
+
]).then((key) => this.storage.key(this.scope, key));
|
|
46982
|
+
}
|
|
46983
|
+
async read(name2) {
|
|
46984
|
+
const id = `${this.scope}:${name2}`;
|
|
46985
|
+
const envelope = await this.storage.read(id);
|
|
46986
|
+
if (!envelope)
|
|
46987
|
+
return;
|
|
46988
|
+
const bytes = await crypto.subtle.decrypt({
|
|
46989
|
+
name: "AES-GCM",
|
|
46990
|
+
iv: envelope.iv,
|
|
46991
|
+
additionalData: new TextEncoder().encode(id)
|
|
46992
|
+
}, await this.encryptionKey(), envelope.data);
|
|
46993
|
+
return JSON.parse(new TextDecoder().decode(bytes));
|
|
46994
|
+
}
|
|
46995
|
+
async write(name2, value2) {
|
|
46996
|
+
const id = `${this.scope}:${name2}`;
|
|
46997
|
+
const iv = crypto.getRandomValues(new Uint8Array(12));
|
|
46998
|
+
const data = await crypto.subtle.encrypt({ name: "AES-GCM", iv, additionalData: new TextEncoder().encode(id) }, await this.encryptionKey(), new TextEncoder().encode(JSON.stringify(value2)));
|
|
46999
|
+
await this.storage.write(id, { iv, data });
|
|
47000
|
+
}
|
|
47001
|
+
}
|
|
47002
|
+
|
|
47003
|
+
class ViewCache {
|
|
47004
|
+
scope;
|
|
47005
|
+
storage;
|
|
47006
|
+
memory = new Map;
|
|
47007
|
+
key;
|
|
47008
|
+
constructor(scope, storage) {
|
|
47009
|
+
this.scope = scope;
|
|
47010
|
+
this.storage = storage;
|
|
47011
|
+
}
|
|
47012
|
+
encryptionKey() {
|
|
47013
|
+
return this.key ??= crypto.subtle.generateKey({ name: "AES-GCM", length: 256 }, false, [
|
|
47014
|
+
"encrypt",
|
|
47015
|
+
"decrypt"
|
|
47016
|
+
]).then((key) => this.storage.key(this.scope, key));
|
|
47017
|
+
}
|
|
47018
|
+
id(kind, account) {
|
|
47019
|
+
return `${this.scope}:${kind}:${account}`;
|
|
47020
|
+
}
|
|
47021
|
+
async get(kind, account, version) {
|
|
47022
|
+
const id = this.id(kind, account);
|
|
47023
|
+
let snapshot = this.memory.get(id);
|
|
47024
|
+
if (!snapshot && this.storage) {
|
|
47025
|
+
try {
|
|
47026
|
+
const envelope = await this.storage.read(id);
|
|
47027
|
+
if (envelope) {
|
|
47028
|
+
const bytes = await crypto.subtle.decrypt({
|
|
47029
|
+
name: "AES-GCM",
|
|
47030
|
+
iv: envelope.iv,
|
|
47031
|
+
additionalData: new TextEncoder().encode(id)
|
|
47032
|
+
}, await this.encryptionKey(), envelope.data);
|
|
47033
|
+
snapshot = JSON.parse(new TextDecoder().decode(bytes), (_, value2) => value2 && typeof value2 === "object" && typeof value2.$bigint === "string" ? BigInt(value2.$bigint) : value2);
|
|
47034
|
+
}
|
|
47035
|
+
} catch {
|
|
47036
|
+
return;
|
|
47037
|
+
}
|
|
47038
|
+
}
|
|
47039
|
+
if (!snapshot || snapshot.status !== "ready" || snapshot.version !== version || typeof snapshot.id !== "string" || !Number.isSafeInteger(snapshot.slot) || (kind === "balance" ? typeof snapshot.amount !== "bigint" : [
|
|
47040
|
+
"collateral",
|
|
47041
|
+
"reserved",
|
|
47042
|
+
"position",
|
|
47043
|
+
"entryPriceE8",
|
|
47044
|
+
"fundingCheckpoint"
|
|
47045
|
+
].some((field) => typeof snapshot[field] !== "bigint")))
|
|
47046
|
+
return;
|
|
47047
|
+
this.memory.set(id, snapshot);
|
|
47048
|
+
return { ...snapshot };
|
|
47049
|
+
}
|
|
47050
|
+
async set(kind, account, snapshot) {
|
|
47051
|
+
if (snapshot.status !== "ready")
|
|
47052
|
+
return;
|
|
47053
|
+
const id = this.id(kind, account);
|
|
47054
|
+
this.memory.set(id, { ...snapshot });
|
|
47055
|
+
if (!this.storage)
|
|
47056
|
+
return;
|
|
47057
|
+
try {
|
|
47058
|
+
const iv = crypto.getRandomValues(new Uint8Array(12));
|
|
47059
|
+
const bytes = new TextEncoder().encode(JSON.stringify(snapshot, (_, value2) => typeof value2 === "bigint" ? { $bigint: value2.toString() } : value2));
|
|
47060
|
+
const data = await crypto.subtle.encrypt({ name: "AES-GCM", iv, additionalData: new TextEncoder().encode(id) }, await this.encryptionKey(), bytes);
|
|
47061
|
+
await this.storage.write(id, { iv, data });
|
|
47062
|
+
} catch {}
|
|
47063
|
+
}
|
|
47064
|
+
}
|
|
47065
|
+
|
|
47066
|
+
// src/view/session.ts
|
|
47067
|
+
var identities = new Map;
|
|
47068
|
+
var approvals = new Map;
|
|
47069
|
+
var requests = new Map;
|
|
47070
|
+
var disabled = new Set;
|
|
47071
|
+
|
|
47072
|
+
class ViewSession {
|
|
47073
|
+
program;
|
|
47074
|
+
connection;
|
|
47075
|
+
owner;
|
|
47076
|
+
serviceUrl;
|
|
47077
|
+
scope;
|
|
47078
|
+
storage;
|
|
47079
|
+
pending = new Map;
|
|
47080
|
+
constructor(program, connection, owner, serviceUrl, scope, storage) {
|
|
47081
|
+
this.program = program;
|
|
47082
|
+
this.connection = connection;
|
|
47083
|
+
this.owner = owner;
|
|
47084
|
+
this.serviceUrl = serviceUrl;
|
|
47085
|
+
this.scope = scope;
|
|
47086
|
+
if (storage)
|
|
47087
|
+
this.storage = new EncryptedViews(scope, storage);
|
|
47088
|
+
}
|
|
47089
|
+
identity() {
|
|
47090
|
+
let value2 = identities.get(this.scope);
|
|
47091
|
+
if (!value2) {
|
|
47092
|
+
value2 = (async () => {
|
|
47093
|
+
const saved = await this.storage?.read("authorization");
|
|
47094
|
+
if (saved) {
|
|
47095
|
+
if (![saved.signing, saved.encryption].every((key) => Array.isArray(key) && key.length === 32 && key.every((v) => Number.isInteger(v) && v >= 0 && v <= 255)))
|
|
47096
|
+
throw new Error("Invalid private read identity");
|
|
47097
|
+
return saved;
|
|
47098
|
+
}
|
|
47099
|
+
const identity = {
|
|
47100
|
+
signing: Array.from(randomBytes3(32)),
|
|
47101
|
+
encryption: Array.from(x25519.utils.randomSecretKey())
|
|
47102
|
+
};
|
|
47103
|
+
await this.storage?.write("authorization", identity);
|
|
47104
|
+
return identity;
|
|
47105
|
+
})();
|
|
47106
|
+
identities.set(this.scope, value2);
|
|
47107
|
+
value2.catch(() => identities.delete(this.scope));
|
|
47108
|
+
}
|
|
47109
|
+
return value2;
|
|
47110
|
+
}
|
|
47111
|
+
async keys() {
|
|
47112
|
+
const identity = await this.identity();
|
|
47113
|
+
const secret = Uint8Array.from(identity.encryption);
|
|
47114
|
+
const signing = Uint8Array.from(identity.signing);
|
|
47115
|
+
const reader = new PublicKey10(await getPublicKey(signing));
|
|
47116
|
+
return {
|
|
47117
|
+
signing,
|
|
47118
|
+
secret,
|
|
47119
|
+
reader,
|
|
47120
|
+
viewKey: x25519.getPublicKey(secret),
|
|
47121
|
+
permit: viewPermitAddress(this.owner, reader)
|
|
47122
|
+
};
|
|
47123
|
+
}
|
|
47124
|
+
async status() {
|
|
47125
|
+
const keys = await this.keys();
|
|
47126
|
+
const info = await this.connection.getAccountInfo(keys.permit, "confirmed");
|
|
47127
|
+
if (!info)
|
|
47128
|
+
return { active: false, id: keys.permit.toBase58() };
|
|
47129
|
+
if (!info.owner.equals(DEPTH_PROGRAM_ID7))
|
|
47130
|
+
throw new Error("Invalid private read permission owner");
|
|
47131
|
+
const permit = this.program.coder.accounts.decode("viewPermit", info.data);
|
|
47132
|
+
const expiresAt = permit.expiresAt.toNumber();
|
|
47133
|
+
if (!permit.owner.equals(this.owner) || !permit.reader.equals(keys.reader) || !permit.market.equals(marketAddress7()) || !Buffer2.from(permit.viewKey).equals(Buffer2.from(keys.viewKey)))
|
|
47134
|
+
throw new Error("Private read permission does not match this device");
|
|
47135
|
+
return {
|
|
47136
|
+
id: keys.permit.toBase58(),
|
|
47137
|
+
active: permit.active && expiresAt > Math.floor(Date.now() / 1000) && permit.scopes === 15,
|
|
47138
|
+
expiresAt
|
|
47139
|
+
};
|
|
47140
|
+
}
|
|
47141
|
+
async capability() {
|
|
47142
|
+
if (!this.serviceUrl)
|
|
47143
|
+
throw new Error("A Depth service is required for automatic private reads");
|
|
47144
|
+
const response = await fetch(`${this.serviceUrl}/v1/views`, {
|
|
47145
|
+
cache: "no-store",
|
|
47146
|
+
signal: AbortSignal.timeout(15000)
|
|
47147
|
+
});
|
|
47148
|
+
if (!response.ok || (await response.json()).enabled !== true)
|
|
47149
|
+
throw new Error("Automatic private reads are unavailable");
|
|
47150
|
+
}
|
|
47151
|
+
async authorize() {
|
|
47152
|
+
const { permit, reader, viewKey } = await this.keys();
|
|
47153
|
+
const id = permit.toBase58();
|
|
47154
|
+
const existing = approvals.get(id);
|
|
47155
|
+
if (existing)
|
|
47156
|
+
return existing;
|
|
47157
|
+
const approval = (async () => {
|
|
47158
|
+
if ((await this.status()).active) {
|
|
47159
|
+
disabled.delete(this.scope);
|
|
47160
|
+
await this.storage?.write("disabled", false);
|
|
47161
|
+
return;
|
|
47162
|
+
}
|
|
47163
|
+
await this.capability();
|
|
47164
|
+
const expiresAt = new anchor8.BN(Math.floor(Date.now() / 1000) + 7 * 86400 - 60);
|
|
47165
|
+
await this.program.methods.authorizeViews(reader, Array.from(viewKey), expiresAt, 15).accountsPartial({ owner: this.owner, market: marketAddress7(), permit }).rpc({ commitment: "confirmed" });
|
|
47166
|
+
disabled.delete(this.scope);
|
|
47167
|
+
await this.storage?.write("disabled", false);
|
|
47168
|
+
})().finally(() => approvals.delete(id));
|
|
47169
|
+
approvals.set(id, approval);
|
|
47170
|
+
return approval;
|
|
47171
|
+
}
|
|
47172
|
+
async revoke() {
|
|
47173
|
+
const { permit } = await this.keys();
|
|
47174
|
+
const signature = await this.program.methods.revokeViews().accountsPartial({ owner: this.owner, permit }).rpc({ commitment: "confirmed" });
|
|
47175
|
+
disabled.add(this.scope);
|
|
47176
|
+
await this.storage?.write("disabled", true);
|
|
47177
|
+
return signature;
|
|
47178
|
+
}
|
|
47179
|
+
async post(request, action) {
|
|
47180
|
+
const { signing } = await this.keys();
|
|
47181
|
+
request.expiresAt = Math.floor(Date.now() / 1000) + 120;
|
|
47182
|
+
request.signature = Buffer2.from(await sign(new TextEncoder().encode(viewMessage(DEPTH_PROGRAM_ID7.toBase58(), request, action)), signing)).toString("base64");
|
|
47183
|
+
return fetch(`${this.serviceUrl}/v1/views${action === "close" ? "/close" : ""}`, {
|
|
47184
|
+
method: "POST",
|
|
47185
|
+
headers: { "content-type": "application/json" },
|
|
47186
|
+
body: JSON.stringify(request),
|
|
47187
|
+
signal: AbortSignal.timeout(60000)
|
|
47188
|
+
});
|
|
47189
|
+
}
|
|
47190
|
+
request(kind, source) {
|
|
47191
|
+
const key = `${this.scope}:${kind}:${source.toBase58()}`;
|
|
47192
|
+
const pending = requests.get(key);
|
|
47193
|
+
if (pending)
|
|
47194
|
+
return pending;
|
|
47195
|
+
const request = this.read(kind, source).finally(() => requests.delete(key));
|
|
47196
|
+
requests.set(key, request);
|
|
47197
|
+
return request;
|
|
47198
|
+
}
|
|
47199
|
+
async read(kind, source, retry = true) {
|
|
47200
|
+
if (disabled.has(this.scope) || await this.storage?.read("disabled"))
|
|
47201
|
+
throw new Error("Private reads are disabled on this device");
|
|
47202
|
+
await this.authorize();
|
|
47203
|
+
const keys = await this.keys();
|
|
47204
|
+
const name2 = `request:${kind}:${source.toBase58()}`;
|
|
47205
|
+
let pending = this.pending.get(name2) ?? await this.storage?.read(name2);
|
|
47206
|
+
if (!pending) {
|
|
47207
|
+
pending = { nonce: new anchor8.BN(randomBytes3(8), "le").toString() };
|
|
47208
|
+
await this.storage?.write(name2, pending);
|
|
47209
|
+
this.pending.set(name2, pending);
|
|
47210
|
+
}
|
|
47211
|
+
const request = {
|
|
47212
|
+
owner: this.owner.toBase58(),
|
|
47213
|
+
reader: keys.reader.toBase58(),
|
|
47214
|
+
permit: keys.permit.toBase58(),
|
|
47215
|
+
kind,
|
|
47216
|
+
source: source.toBase58(),
|
|
47217
|
+
nonce: pending.nonce,
|
|
47218
|
+
expiresAt: 0,
|
|
47219
|
+
signature: ""
|
|
47220
|
+
};
|
|
47221
|
+
const response = await this.post(request, "read");
|
|
47222
|
+
if (response.status === 410 && retry) {
|
|
47223
|
+
this.pending.delete(name2);
|
|
47224
|
+
await this.storage?.write(name2, null);
|
|
47225
|
+
return this.read(kind, source, false);
|
|
47226
|
+
}
|
|
47227
|
+
if (!response.ok) {
|
|
47228
|
+
const error = await response.json().catch(() => ({}));
|
|
47229
|
+
if (error.error === "view_source_busy")
|
|
47230
|
+
throw new Error("Private account is processing another operation");
|
|
47231
|
+
throw new Error(`Private read service returned HTTP ${response.status}`);
|
|
47232
|
+
}
|
|
47233
|
+
const receipt = await response.json();
|
|
47234
|
+
const payer = new PublicKey10(receipt.payer);
|
|
47235
|
+
const nonce = new anchor8.BN(request.nonce).toArrayLike(Buffer2, "le", 8);
|
|
47236
|
+
const seeds = kind === "balance" ? [Buffer2.from("view"), payer.toBuffer(), nonce] : kind === "market" ? [Buffer2.from("market-view"), source.toBuffer(), nonce] : [
|
|
47237
|
+
Buffer2.from(`${kind}-view`),
|
|
47238
|
+
source.toBuffer(),
|
|
47239
|
+
payer.toBuffer(),
|
|
47240
|
+
nonce
|
|
47241
|
+
];
|
|
47242
|
+
const id = PublicKey10.findProgramAddressSync(seeds, DEPTH_PROGRAM_ID7)[0];
|
|
47243
|
+
if (receipt.id !== id.toBase58() || typeof receipt.signature !== "string")
|
|
47244
|
+
throw new Error("Invalid private read receipt");
|
|
47245
|
+
const mxeKey = await getMXEPublicKey(this.program.provider, DEPTH_PROGRAM_ID7);
|
|
47246
|
+
if (!mxeKey)
|
|
47247
|
+
throw new Error("MXE public key is unavailable");
|
|
47248
|
+
return new DepthView(id, receipt.signature, kind, payer, keys.secret, keys.viewKey, mxeKey, this.program, this.connection, source, async () => {
|
|
47249
|
+
this.pending.delete(name2);
|
|
47250
|
+
await this.storage?.write(name2, null);
|
|
47251
|
+
try {
|
|
47252
|
+
await this.post(request, "close");
|
|
47253
|
+
} catch {}
|
|
47254
|
+
return "";
|
|
47255
|
+
});
|
|
46815
47256
|
}
|
|
46816
47257
|
}
|
|
46817
47258
|
|
|
46818
47259
|
// src/client/client.ts
|
|
46819
|
-
function pda(seeds, programId =
|
|
46820
|
-
return
|
|
47260
|
+
function pda(seeds, programId = DEPTH_PROGRAM_ID8) {
|
|
47261
|
+
return PublicKey11.findProgramAddressSync(seeds, programId)[0];
|
|
46821
47262
|
}
|
|
46822
47263
|
function nonce() {
|
|
46823
|
-
return new
|
|
47264
|
+
return new anchor9.BN(randomBytes3(8), "le");
|
|
46824
47265
|
}
|
|
46825
47266
|
function enumName2(value2) {
|
|
46826
47267
|
return Object.keys(value2)[0] ?? "unknown";
|
|
@@ -46830,15 +47271,18 @@ class DepthClient {
|
|
|
46830
47271
|
options;
|
|
46831
47272
|
program;
|
|
46832
47273
|
provider;
|
|
47274
|
+
viewCache;
|
|
47275
|
+
views;
|
|
47276
|
+
viewReads = new Map;
|
|
46833
47277
|
position;
|
|
46834
|
-
marketAddress =
|
|
47278
|
+
marketAddress = marketAddress8();
|
|
46835
47279
|
protocolAddress = protocolAddress4();
|
|
46836
|
-
mxeAddress = getMXEAccAddress(
|
|
47280
|
+
mxeAddress = getMXEAccAddress(DEPTH_PROGRAM_ID8);
|
|
46837
47281
|
get catalog() {
|
|
46838
47282
|
return new MarketCatalog(this);
|
|
46839
47283
|
}
|
|
46840
47284
|
get funding() {
|
|
46841
|
-
return new FundingClient(this.program, this.options.connection, this.options.wallet.publicKey, (name2, offset2) => this.queue(name2, offset2));
|
|
47285
|
+
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
47286
|
}
|
|
46843
47287
|
get app() {
|
|
46844
47288
|
return new AppAdmin(this.program, this.options.connection, this.options.wallet.publicKey, this.funding);
|
|
@@ -46852,15 +47296,19 @@ class DepthClient {
|
|
|
46852
47296
|
}
|
|
46853
47297
|
constructor(options) {
|
|
46854
47298
|
this.options = options;
|
|
47299
|
+
const scope = `${"manifest" in options.deployment ? options.deployment.manifest.payload.genesisHash : "localnet"}:${DEPTH_PROGRAM_ID8.toBase58()}:${options.wallet.publicKey.toBase58()}`;
|
|
47300
|
+
const storage = options.privateViews === "device" && "manifest" in options.deployment && typeof indexedDB !== "undefined" && globalThis.crypto?.subtle ? new DeviceViews : undefined;
|
|
47301
|
+
this.viewCache = new ViewCache(scope, storage);
|
|
46855
47302
|
this.provider = new DepthProvider(options.connection, options.wallet, {
|
|
46856
47303
|
commitment: "confirmed",
|
|
46857
47304
|
preflightCommitment: "confirmed"
|
|
46858
47305
|
});
|
|
46859
|
-
this.program = new
|
|
47306
|
+
this.program = new anchor9.Program(DEPTH_IDL3, this.provider);
|
|
47307
|
+
this.views = new ViewSession(this.program, options.connection, options.wallet.publicKey, options.serviceUrl, scope, storage);
|
|
46860
47308
|
this.position = this.positionActions();
|
|
46861
47309
|
}
|
|
46862
47310
|
static async create(options) {
|
|
46863
|
-
const appId = typeof options.appId === "string" ? new
|
|
47311
|
+
const appId = typeof options.appId === "string" ? new PublicKey11(options.appId) : options.appId;
|
|
46864
47312
|
const resolved = {
|
|
46865
47313
|
...options,
|
|
46866
47314
|
...await resolveConnection(options),
|
|
@@ -46873,7 +47321,7 @@ class DepthClient {
|
|
|
46873
47321
|
}
|
|
46874
47322
|
async verifyDeployment() {
|
|
46875
47323
|
const [programInfo, protocol, market, app, mxe] = await Promise.all([
|
|
46876
|
-
this.options.connection.getAccountInfo(
|
|
47324
|
+
this.options.connection.getAccountInfo(DEPTH_PROGRAM_ID8, "confirmed"),
|
|
46877
47325
|
this.read("Protocol", this.protocolAddress),
|
|
46878
47326
|
this.read("Market", this.marketAddress),
|
|
46879
47327
|
this.options.appId ? this.read("AppConfig", appAddress2(this.options.appId)) : Promise.resolve(undefined),
|
|
@@ -46881,13 +47329,13 @@ class DepthClient {
|
|
|
46881
47329
|
]);
|
|
46882
47330
|
if (!programInfo?.executable)
|
|
46883
47331
|
throw new Error("Depth program is not deployed");
|
|
46884
|
-
if (!market.settlementMint.equals(protocol.settlementMint) || !market.vault.equals(protocol.vault) || this.options.appId && !app?.app.equals(this.options.appId) || !mxe.mxeProgramId.equals(
|
|
47332
|
+
if (!market.settlementMint.equals(protocol.settlementMint) || !market.vault.equals(protocol.vault) || this.options.appId && !app?.app.equals(this.options.appId) || !mxe.mxeProgramId.equals(DEPTH_PROGRAM_ID8)) {
|
|
46885
47333
|
throw new Error("Depth deployment accounts disagree");
|
|
46886
47334
|
}
|
|
46887
47335
|
}
|
|
46888
47336
|
async read(name2, address2) {
|
|
46889
47337
|
const info = await this.options.connection.getAccountInfo(address2, "confirmed");
|
|
46890
|
-
if (!info || !info.owner.equals(
|
|
47338
|
+
if (!info || !info.owner.equals(DEPTH_PROGRAM_ID8)) {
|
|
46891
47339
|
throw new Error(`${name2} account is unavailable`);
|
|
46892
47340
|
}
|
|
46893
47341
|
return this.program.coder.accounts.decode(name2[0].toLowerCase() + name2.slice(1), info.data);
|
|
@@ -46895,7 +47343,7 @@ class DepthClient {
|
|
|
46895
47343
|
async queue(name2, offset2) {
|
|
46896
47344
|
const mxe = await arciumAccount(this.provider).fetch(this.mxeAddress);
|
|
46897
47345
|
const cluster = mxe.cluster;
|
|
46898
|
-
const definition = getCompDefAccAddress(
|
|
47346
|
+
const definition = getCompDefAccAddress(DEPTH_PROGRAM_ID8, Buffer2.from(getCompDefAccOffset(computationName(name2))).readUInt32LE());
|
|
46899
47347
|
const definitionInfo = await this.options.connection.getAccountInfo(definition, "confirmed");
|
|
46900
47348
|
if (!definitionInfo)
|
|
46901
47349
|
throw new Error(`${name2} computation is not deployed`);
|
|
@@ -46917,7 +47365,7 @@ class DepthClient {
|
|
|
46917
47365
|
}
|
|
46918
47366
|
async market() {
|
|
46919
47367
|
const response = await this.options.connection.getAccountInfoAndContext(this.marketAddress, "confirmed");
|
|
46920
|
-
if (!response.value || !response.value.owner.equals(
|
|
47368
|
+
if (!response.value || !response.value.owner.equals(DEPTH_PROGRAM_ID8)) {
|
|
46921
47369
|
throw new Error("Depth market is unavailable");
|
|
46922
47370
|
}
|
|
46923
47371
|
return {
|
|
@@ -46929,6 +47377,9 @@ class DepthClient {
|
|
|
46929
47377
|
operation(id) {
|
|
46930
47378
|
return new DepthOperation(id, undefined, this.program, this.options.connection, (order) => this.requestFillView(order));
|
|
46931
47379
|
}
|
|
47380
|
+
async requestQuoteView(quote) {
|
|
47381
|
+
return this.views.request("quote", quote);
|
|
47382
|
+
}
|
|
46932
47383
|
async requestBalanceView() {
|
|
46933
47384
|
const owner = this.options.wallet.publicKey;
|
|
46934
47385
|
const balance = pda([Buffer2.from("balance"), owner.toBuffer()]);
|
|
@@ -46976,7 +47427,10 @@ class DepthClient {
|
|
|
46976
47427
|
return this.requestView("fill", view, viewNonce, { order });
|
|
46977
47428
|
}
|
|
46978
47429
|
async requestView(kind, view, viewNonce, accounts2) {
|
|
46979
|
-
const
|
|
47430
|
+
const source = accounts2.balance ?? accounts2.marketAccount ?? accounts2.order;
|
|
47431
|
+
if (this.options.viewAuthorization === "session" || this.options.viewAuthorization !== "wallet" && this.options.privateViews === "device" && this.options.serviceUrl)
|
|
47432
|
+
return this.views.request(kind, source);
|
|
47433
|
+
const mxePublicKey = await getMXEPublicKey(this.provider, DEPTH_PROGRAM_ID8);
|
|
46980
47434
|
if (!mxePublicKey)
|
|
46981
47435
|
throw new Error("MXE public key is unavailable");
|
|
46982
47436
|
const secret = x25519.utils.randomSecretKey();
|
|
@@ -46991,7 +47445,7 @@ class DepthClient {
|
|
|
46991
47445
|
...kind === "balance" ? {} : { grant: null },
|
|
46992
47446
|
view
|
|
46993
47447
|
}).rpc({ commitment: "confirmed" });
|
|
46994
|
-
return new DepthView(view, signature, kind, this.options.wallet.publicKey, secret, publicKey, mxePublicKey, this.program, this.options.connection);
|
|
47448
|
+
return new DepthView(view, signature, kind, this.options.wallet.publicKey, secret, publicKey, mxePublicKey, this.program, this.options.connection, source);
|
|
46995
47449
|
}
|
|
46996
47450
|
async ensureBalanceReady() {
|
|
46997
47451
|
const address2 = this.funding.balance;
|
|
@@ -47078,7 +47532,7 @@ class DepthClient {
|
|
|
47078
47532
|
return this.funding.release(amount, clientNonce ?? BigInt(nonce().toString()));
|
|
47079
47533
|
}
|
|
47080
47534
|
async depositRequest(sourceOrAmount, amount, clientNonce) {
|
|
47081
|
-
if (sourceOrAmount instanceof
|
|
47535
|
+
if (sourceOrAmount instanceof PublicKey11) {
|
|
47082
47536
|
if (amount === undefined || clientNonce === undefined)
|
|
47083
47537
|
throw new RangeError("Source deposits require amount and client nonce");
|
|
47084
47538
|
return this.funding.deposit(sourceOrAmount, amount, clientNonce);
|
|
@@ -47089,7 +47543,7 @@ class DepthClient {
|
|
|
47089
47543
|
return this.funding.deposit(source, sourceOrAmount, amount ?? BigInt(nonce().toString()));
|
|
47090
47544
|
}
|
|
47091
47545
|
async withdrawRequest(destinationOrAmount, amount, clientNonce) {
|
|
47092
|
-
if (destinationOrAmount instanceof
|
|
47546
|
+
if (destinationOrAmount instanceof PublicKey11) {
|
|
47093
47547
|
if (amount === undefined || clientNonce === undefined)
|
|
47094
47548
|
throw new RangeError("Destination withdrawals require amount and client nonce");
|
|
47095
47549
|
return this.funding.withdraw(destinationOrAmount, amount, clientNonce);
|
|
@@ -47124,11 +47578,7 @@ class DepthClient {
|
|
|
47124
47578
|
const state = await actions.state();
|
|
47125
47579
|
if (state.status === "uninitialized")
|
|
47126
47580
|
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;
|
|
47581
|
+
return this.summaryView("balance", state.id, options);
|
|
47132
47582
|
}
|
|
47133
47583
|
};
|
|
47134
47584
|
return Object.assign(() => actions, actions);
|
|
@@ -47164,29 +47614,7 @@ class DepthClient {
|
|
|
47164
47614
|
summary: async (options = {
|
|
47165
47615
|
timeoutMs: 180000
|
|
47166
47616
|
}) => {
|
|
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;
|
|
47617
|
+
return this.summaryView("market", address2.toBase58(), options);
|
|
47190
47618
|
}
|
|
47191
47619
|
};
|
|
47192
47620
|
return Object.assign((positionId) => this.positionActions(positionId), actions);
|
|
@@ -47232,6 +47660,75 @@ class DepthClient {
|
|
|
47232
47660
|
u64(clientNonce, "clientNonce").toArrayLike(Buffer2, "le", 8)
|
|
47233
47661
|
]);
|
|
47234
47662
|
}
|
|
47663
|
+
async deferViewClose(kind, id) {
|
|
47664
|
+
const view = new PublicKey11(id);
|
|
47665
|
+
const method = kind === "balance" ? this.program.methods.closeBalanceView : this.program.methods.closeMarketView;
|
|
47666
|
+
this.provider.deferClose(view, await method().accountsPartial({
|
|
47667
|
+
owner: this.options.wallet.publicKey,
|
|
47668
|
+
view
|
|
47669
|
+
}).instruction());
|
|
47670
|
+
}
|
|
47671
|
+
async viewState(kind, id) {
|
|
47672
|
+
if (kind === "balance")
|
|
47673
|
+
return this.account().state();
|
|
47674
|
+
const state = await this.read("MarketAccount", new PublicKey11(id));
|
|
47675
|
+
if (!state.owner.equals(this.options.wallet.publicKey) || !state.market.equals(this.marketAddress))
|
|
47676
|
+
throw new Error("Position does not belong to this wallet and market");
|
|
47677
|
+
return {
|
|
47678
|
+
status: enumName2(state.status),
|
|
47679
|
+
version: BigInt(state.version.toString())
|
|
47680
|
+
};
|
|
47681
|
+
}
|
|
47682
|
+
summaryView(kind, id, options) {
|
|
47683
|
+
const key = `${kind}:${id}`;
|
|
47684
|
+
const pending = this.viewReads.get(key);
|
|
47685
|
+
if (pending)
|
|
47686
|
+
return pending;
|
|
47687
|
+
const request = this.readSummaryView(kind, id, options).finally(() => {
|
|
47688
|
+
if (this.viewReads.get(key) === request)
|
|
47689
|
+
this.viewReads.delete(key);
|
|
47690
|
+
});
|
|
47691
|
+
this.viewReads.set(key, request);
|
|
47692
|
+
return request;
|
|
47693
|
+
}
|
|
47694
|
+
async readSummaryView(kind, id, options) {
|
|
47695
|
+
if (!Number.isSafeInteger(options.timeoutMs) || options.timeoutMs < 0)
|
|
47696
|
+
throw new RangeError("timeoutMs must be a nonnegative integer");
|
|
47697
|
+
const deadline = Date.now() + options.timeoutMs;
|
|
47698
|
+
for (;; ) {
|
|
47699
|
+
const state = await this.viewState(kind, id);
|
|
47700
|
+
if (state.status === "ready") {
|
|
47701
|
+
const cached = await this.viewCache.get(kind, id, state.version);
|
|
47702
|
+
if (cached) {
|
|
47703
|
+
await this.deferViewClose(kind, cached.id);
|
|
47704
|
+
return cached;
|
|
47705
|
+
}
|
|
47706
|
+
try {
|
|
47707
|
+
const view = kind === "balance" ? await this.requestBalanceView() : await this.requestMarketView();
|
|
47708
|
+
const result = await view.wait({
|
|
47709
|
+
...options,
|
|
47710
|
+
timeoutMs: Math.max(0, deadline - Date.now())
|
|
47711
|
+
});
|
|
47712
|
+
if (result.status === "pending")
|
|
47713
|
+
return result;
|
|
47714
|
+
await view.deferClose();
|
|
47715
|
+
const latest = await this.viewState(kind, id);
|
|
47716
|
+
if (result.status === "ready" && latest.status === "ready" && latest.version === result.version) {
|
|
47717
|
+
const snapshot = { ...result, readAt: Date.now() };
|
|
47718
|
+
await this.viewCache.set(kind, id, snapshot);
|
|
47719
|
+
return snapshot;
|
|
47720
|
+
}
|
|
47721
|
+
} catch (error) {
|
|
47722
|
+
const code2 = error.error?.errorCode?.code;
|
|
47723
|
+
if (code2 !== "WrongMarketAccountStatus" && !String(error).includes("processing another operation"))
|
|
47724
|
+
throw error;
|
|
47725
|
+
}
|
|
47726
|
+
}
|
|
47727
|
+
if (Date.now() >= deadline)
|
|
47728
|
+
throw new Error("Private account is still processing an operation");
|
|
47729
|
+
await new Promise((resolve) => setTimeout(resolve, Math.min(options.pollMs ?? 1000, deadline - Date.now())));
|
|
47730
|
+
}
|
|
47731
|
+
}
|
|
47235
47732
|
async submitTrade(input, intent) {
|
|
47236
47733
|
const appId = this.options.appId;
|
|
47237
47734
|
if (!appId)
|
|
@@ -47263,43 +47760,13 @@ class DepthClient {
|
|
|
47263
47760
|
throw new Error("Position does not belong to this wallet and market");
|
|
47264
47761
|
await this.ensureBalanceReady();
|
|
47265
47762
|
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);
|
|
47763
|
+
let [market, protocol, account, app] = await this.waitForMarket(input, appId, intent);
|
|
47764
|
+
let deadline;
|
|
47273
47765
|
tradeLimit(input, "long", BigInt(market.state.oraclePriceE8.toString()));
|
|
47274
|
-
this.validateTrade(market.state, protocol, account, app, appId, intent, deadline);
|
|
47275
47766
|
if (additionalMargin > 0n) {
|
|
47276
47767
|
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);
|
|
47768
|
+
await transfer.confirm({ timeoutMs: 120000 });
|
|
47769
|
+
[market, protocol, account, app] = await this.waitForMarket(input, appId, intent);
|
|
47303
47770
|
}
|
|
47304
47771
|
const viewDeadline = Date.now() + 120000;
|
|
47305
47772
|
let position;
|
|
@@ -47317,15 +47784,13 @@ class DepthClient {
|
|
|
47317
47784
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
47318
47785
|
continue;
|
|
47319
47786
|
}
|
|
47320
|
-
[market, account] = await
|
|
47321
|
-
this.market(),
|
|
47322
|
-
this.read("MarketAccount", this.accountAddress())
|
|
47323
|
-
]);
|
|
47787
|
+
[market, protocol, account, app] = await this.waitForMarket(input, appId, intent);
|
|
47324
47788
|
if (position.status === "ready" && enumName2(account.status) === "ready" && account.version.toString() === position.version.toString()) {
|
|
47325
47789
|
break;
|
|
47326
47790
|
}
|
|
47327
47791
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
47328
47792
|
}
|
|
47793
|
+
deadline = tradeDeadline(input, Math.floor(Date.now() / 1000), market.state.config.maxOrderQueueSeconds);
|
|
47329
47794
|
this.validateTrade(market.state, protocol, account, app, appId, intent, deadline);
|
|
47330
47795
|
if (position.status !== "ready" || position.collateral === undefined || position.position === undefined)
|
|
47331
47796
|
throw new Error(`Private position view ${position.id} is ${position.status}`);
|
|
@@ -47350,11 +47815,11 @@ class DepthClient {
|
|
|
47350
47815
|
const keys = [market.state.backstopOffer, ...quotes];
|
|
47351
47816
|
const records = await this.options.connection.getMultipleAccountsInfo(keys, "confirmed");
|
|
47352
47817
|
records.forEach((info, index) => {
|
|
47353
|
-
if (!info?.owner.equals(
|
|
47818
|
+
if (!info?.owner.equals(DEPTH_PROGRAM_ID8)) {
|
|
47354
47819
|
throw new Error(`Market quote snapshot missing account ${index}`);
|
|
47355
47820
|
}
|
|
47356
47821
|
});
|
|
47357
|
-
const mxePublicKey = await getMXEPublicKey(this.provider,
|
|
47822
|
+
const mxePublicKey = await getMXEPublicKey(this.provider, DEPTH_PROGRAM_ID8);
|
|
47358
47823
|
if (!mxePublicKey)
|
|
47359
47824
|
throw new Error("MXE public key is unavailable");
|
|
47360
47825
|
const secret = x25519.utils.randomSecretKey();
|
|
@@ -47372,7 +47837,7 @@ class DepthClient {
|
|
|
47372
47837
|
}), inputNonce);
|
|
47373
47838
|
const offset2 = nonce();
|
|
47374
47839
|
const queue = await this.queue("match_order", offset2);
|
|
47375
|
-
const signature = await this.program.methods.submitOrder(offset2, orderNonce, appId, app.feeBps, app.version, new
|
|
47840
|
+
const signature = await this.program.methods.submitOrder(offset2, orderNonce, appId, app.feeBps, app.version, new anchor9.BN(deadline), market.state.revision, market.state.oracleTimestamp, ciphertexts, Array.from(inputKey), new anchor9.BN(inputNonce, "le")).accountsPartial({
|
|
47376
47841
|
...queue,
|
|
47377
47842
|
trader: this.options.wallet.publicKey,
|
|
47378
47843
|
protocol: this.protocolAddress,
|
|
@@ -47395,6 +47860,29 @@ class DepthClient {
|
|
|
47395
47860
|
]).rpc({ commitment: "confirmed" }).catch((error) => submissionError(order.toBase58(), error));
|
|
47396
47861
|
return new DepthOperation(order, signature, this.program, this.options.connection, (id) => this.requestFillView(id), position);
|
|
47397
47862
|
}
|
|
47863
|
+
async waitForMarket(input, appId, intent) {
|
|
47864
|
+
const until = Date.now() + 60000;
|
|
47865
|
+
for (;; ) {
|
|
47866
|
+
const [market, protocol, account, app] = await Promise.all([
|
|
47867
|
+
this.market(),
|
|
47868
|
+
this.read("Protocol", this.protocolAddress),
|
|
47869
|
+
this.read("MarketAccount", this.accountAddress()),
|
|
47870
|
+
this.read("AppConfig", appAddress2(appId))
|
|
47871
|
+
]);
|
|
47872
|
+
const deadline = tradeDeadline(input, Math.floor(Date.now() / 1000), market.state.config.maxOrderQueueSeconds);
|
|
47873
|
+
try {
|
|
47874
|
+
this.validateTrade(market.state, protocol, account, app, appId, intent, deadline);
|
|
47875
|
+
return [market, protocol, account, app];
|
|
47876
|
+
} catch (error) {
|
|
47877
|
+
if (!(error instanceof Error) || ![
|
|
47878
|
+
"Waiting for maker liquidity",
|
|
47879
|
+
"Market is processing another order"
|
|
47880
|
+
].includes(error.message) || Date.now() >= until)
|
|
47881
|
+
throw error;
|
|
47882
|
+
}
|
|
47883
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
47884
|
+
}
|
|
47885
|
+
}
|
|
47398
47886
|
validateTrade(market, protocol, account, app, appId, intent = "increase", deadline) {
|
|
47399
47887
|
const now = Math.floor(Date.now() / 1000);
|
|
47400
47888
|
const marketStatus = enumName2(market.status);
|
|
@@ -47407,9 +47895,10 @@ class DepthClient {
|
|
|
47407
47895
|
if (enumName2(account.status) !== "ready" || !account.market.equals(this.marketAddress) || !account.owner.equals(this.options.wallet.publicKey)) {
|
|
47408
47896
|
throw new Error("Market account is unavailable");
|
|
47409
47897
|
}
|
|
47410
|
-
if (market.pendingOrders !== 0
|
|
47411
|
-
throw new Error("Market is processing another order
|
|
47412
|
-
|
|
47898
|
+
if (market.pendingOrders !== 0)
|
|
47899
|
+
throw new Error("Market is processing another order");
|
|
47900
|
+
if (market.activeQuoteCount === 0)
|
|
47901
|
+
throw new Error("Waiting for maker liquidity");
|
|
47413
47902
|
const age = now - market.oracleTimestamp.toNumber();
|
|
47414
47903
|
if (age < 0 || age > market.config.maxOracleAgeSeconds) {
|
|
47415
47904
|
throw new Error("Oracle update is stale");
|
|
@@ -47572,6 +48061,7 @@ export {
|
|
|
47572
48061
|
captureDeployment,
|
|
47573
48062
|
authenticateManifest,
|
|
47574
48063
|
WithdrawalHandle,
|
|
48064
|
+
ViewSession,
|
|
47575
48065
|
TransferHandle,
|
|
47576
48066
|
TradeFlow,
|
|
47577
48067
|
MarketData,
|