@depthhq/maker-sdk 0.1.16 → 0.1.17
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/chain/clock.d.ts +2 -0
- package/dist/index.js +49 -36
- package/dist/index.node.js +51 -36
- package/dist/node.js +74 -29
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1313,6 +1313,19 @@ var resolveObjectURL = notimpl("resolveObjectURL");
|
|
|
1313
1313
|
var isUtf8 = notimpl("isUtf8");
|
|
1314
1314
|
var transcode = notimpl("transcode");
|
|
1315
1315
|
|
|
1316
|
+
// src/chain/clock.ts
|
|
1317
|
+
import { PublicKey, SYSVAR_CLOCK_PUBKEY } from "@solana/web3.js";
|
|
1318
|
+
var owner = new PublicKey("Sysvar1111111111111111111111111111111111111");
|
|
1319
|
+
async function chainTime(connection) {
|
|
1320
|
+
const clock = await connection.getAccountInfo(SYSVAR_CLOCK_PUBKEY, "confirmed");
|
|
1321
|
+
if (!clock?.owner.equals(owner) || clock.data.length !== 40)
|
|
1322
|
+
throw new Error("Solana clock sysvar is unavailable");
|
|
1323
|
+
const time = clock.data.readBigInt64LE(32);
|
|
1324
|
+
if (time <= 0n || time > BigInt(Number.MAX_SAFE_INTEGER))
|
|
1325
|
+
throw new Error("Solana clock timestamp is invalid");
|
|
1326
|
+
return Number(time);
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1316
1329
|
// src/client/client.ts
|
|
1317
1330
|
import * as anchor6 from "@anchor-lang/core";
|
|
1318
1331
|
|
|
@@ -3722,7 +3735,7 @@ var { default: fs} = (() => ({}));
|
|
|
3722
3735
|
import * as anchor from "@anchor-lang/core";
|
|
3723
3736
|
import * as anchor__default from "@anchor-lang/core";
|
|
3724
3737
|
import { BorshCoder, convertIdlToCamelCase, Program } from "@anchor-lang/core";
|
|
3725
|
-
import { AddressLookupTableProgram, PublicKey } from "@solana/web3.js";
|
|
3738
|
+
import { AddressLookupTableProgram, PublicKey as PublicKey2 } from "@solana/web3.js";
|
|
3726
3739
|
var CURVE25519_SCALAR_FIELD_MODULUS = ed25519.CURVE.n;
|
|
3727
3740
|
function serializeLE(val, lengthInBytes) {
|
|
3728
3741
|
const result = new Uint8Array(lengthInBytes);
|
|
@@ -26329,7 +26342,7 @@ function findArciumPda(seeds) {
|
|
|
26329
26342
|
return findPda(getArciumProgramId(), seeds);
|
|
26330
26343
|
}
|
|
26331
26344
|
function findPda(programId, seeds) {
|
|
26332
|
-
return
|
|
26345
|
+
return PublicKey2.findProgramAddressSync(seeds, programId)[0];
|
|
26333
26346
|
}
|
|
26334
26347
|
function assertIntegerInRange(value, min, max, label) {
|
|
26335
26348
|
if (!Number.isInteger(value) || value < min || value > max) {
|
|
@@ -26401,7 +26414,7 @@ import {
|
|
|
26401
26414
|
} from "@depthhq/bindings";
|
|
26402
26415
|
import { DepthView } from "@depthhq/sdk/views";
|
|
26403
26416
|
import { DepthRecovery } from "@depthhq/sdk/recovery";
|
|
26404
|
-
import { PublicKey as
|
|
26417
|
+
import { PublicKey as PublicKey8 } from "@solana/web3.js";
|
|
26405
26418
|
|
|
26406
26419
|
// src/chain/random.ts
|
|
26407
26420
|
function randomBytes3(length) {
|
|
@@ -26421,8 +26434,8 @@ function order(value, receipt = false) {
|
|
|
26421
26434
|
return true;
|
|
26422
26435
|
return ["filled", "cancelled", "rejected"].includes(String(value.status)) && integer(value.completedAt) && value.completedAt >= value.nonce && amount(value.filledSize) && BigInt(value.filledSize) >= 0n && BigInt(value.filledSize) <= BigInt(value.size) && (value.filledAt === undefined || integer(value.filledAt) && value.filledAt >= value.nonce - 1000 && value.filledAt <= value.completedAt + 1000) && optional(value.orderId, integer) && optional(value.averagePriceE8, amount) && optional(value.fee, amount) && optional(value.reason, text) && optional(value.hashes, (hashes) => Array.isArray(hashes) && hashes.length <= 2000 && hashes.every((hash) => typeof hash === "string" && /^0x[0-9a-fA-F]{64}$/.test(hash)));
|
|
26423
26436
|
}
|
|
26424
|
-
function hedgeView(value,
|
|
26425
|
-
if (!object(value) || value.maker !==
|
|
26437
|
+
function hedgeView(value, owner2) {
|
|
26438
|
+
if (!object(value) || value.maker !== owner2 || typeof value.enabled !== "boolean")
|
|
26426
26439
|
throw new Error("Maker hedge response belongs to another wallet or is invalid");
|
|
26427
26440
|
const snapshot = value.snapshot;
|
|
26428
26441
|
if (snapshot !== null && (!value.enabled || !object(snapshot) || snapshot.venue !== "hyperliquid" || !["testnet", "mainnet"].includes(String(snapshot.network)) || typeof snapshot.account !== "string" || !/^0x[0-9a-fA-F]{40}$/.test(snapshot.account) || !integer(snapshot.updatedAt) || !["balanced", "waiting", "pending", "blocked"].includes(String(snapshot.phase)) || !optional(snapshot.reason, text) || !optional(snapshot.depthPosition, amount) || !optional(snapshot.externalPosition, amount) || !optional(snapshot.unhedgedPosition, amount) || !optional(snapshot.pending, order) || !Array.isArray(snapshot.history) || snapshot.history.length > 50 || !snapshot.history.every((record) => order(record, true))))
|
|
@@ -26513,7 +26526,7 @@ class MakerAccess extends WalletSession {
|
|
|
26513
26526
|
}
|
|
26514
26527
|
|
|
26515
26528
|
// src/automation/automation.ts
|
|
26516
|
-
import { PublicKey as
|
|
26529
|
+
import { PublicKey as PublicKey4, SystemProgram, Transaction } from "@solana/web3.js";
|
|
26517
26530
|
|
|
26518
26531
|
// src/hedge/setup.ts
|
|
26519
26532
|
import { ExchangeClient, HttpTransport, InfoClient } from "@nktkas/hyperliquid";
|
|
@@ -26600,7 +26613,7 @@ async function setup_hyperliquid(options) {
|
|
|
26600
26613
|
}
|
|
26601
26614
|
|
|
26602
26615
|
// src/automation/types.ts
|
|
26603
|
-
import { PublicKey as
|
|
26616
|
+
import { PublicKey as PublicKey3 } from "@solana/web3.js";
|
|
26604
26617
|
|
|
26605
26618
|
// src/bot/policy.ts
|
|
26606
26619
|
import { positionPnl } from "@depthhq/sdk";
|
|
@@ -26733,7 +26746,7 @@ function automationConfig(value) {
|
|
|
26733
26746
|
};
|
|
26734
26747
|
}
|
|
26735
26748
|
var automationWire = (config) => JSON.parse(JSON.stringify(config, (_key, value) => typeof value === "bigint" ? value.toString() : value));
|
|
26736
|
-
function automationView(value,
|
|
26749
|
+
function automationView(value, owner2, environment) {
|
|
26737
26750
|
if (value === null)
|
|
26738
26751
|
return null;
|
|
26739
26752
|
const view = object2(value, [
|
|
@@ -26751,9 +26764,9 @@ function automationView(value, owner, environment) {
|
|
|
26751
26764
|
"hedge",
|
|
26752
26765
|
"funding"
|
|
26753
26766
|
]);
|
|
26754
|
-
if (view.owner !==
|
|
26767
|
+
if (view.owner !== owner2 || view.environment !== environment)
|
|
26755
26768
|
throw new Error("Automation belongs to another wallet or network");
|
|
26756
|
-
if (typeof view.operator !== "string" || new
|
|
26769
|
+
if (typeof view.operator !== "string" || new PublicKey3(view.operator).toBase58() !== view.operator || typeof view.agent !== "string" || !/^0x[0-9a-fA-F]{40}$/.test(view.agent) || integer2(view.revision) < 1 || integer2(view.updatedAt) < 1 || !["running", "paused"].includes(String(view.desired)) || ![
|
|
26757
26770
|
"configured",
|
|
26758
26771
|
"starting",
|
|
26759
26772
|
"running",
|
|
@@ -26765,10 +26778,10 @@ function automationView(value, owner, environment) {
|
|
|
26765
26778
|
automationConfig(view.config);
|
|
26766
26779
|
if (view.bot !== undefined) {
|
|
26767
26780
|
const bot = object2(view.bot, ["phase", "reason", "quoteId", "fillCount"]);
|
|
26768
|
-
if (!["active", "pending", "idle", "stopped"].includes(String(bot.phase)) || integer2(bot.fillCount) < 0 || bot.reason !== undefined && typeof bot.reason !== "string" || bot.quoteId !== undefined && (typeof bot.quoteId !== "string" || new
|
|
26781
|
+
if (!["active", "pending", "idle", "stopped"].includes(String(bot.phase)) || integer2(bot.fillCount) < 0 || bot.reason !== undefined && typeof bot.reason !== "string" || bot.quoteId !== undefined && (typeof bot.quoteId !== "string" || new PublicKey3(bot.quoteId).toBase58() !== bot.quoteId))
|
|
26769
26782
|
throw new Error("Automation status is invalid");
|
|
26770
26783
|
}
|
|
26771
|
-
hedgeView(view.hedge,
|
|
26784
|
+
hedgeView(view.hedge, owner2);
|
|
26772
26785
|
if (view.funding !== undefined) {
|
|
26773
26786
|
const funding = object2(view.funding, ["signature", "lamports", "status"]);
|
|
26774
26787
|
if (typeof funding.signature !== "string" || !/^[1-9A-HJ-NP-Za-km-z]{64,90}$/.test(funding.signature) || !["pending", "confirmed", "expired", "failed"].includes(String(funding.status)))
|
|
@@ -26840,7 +26853,7 @@ class MakerAutomation extends WalletSession {
|
|
|
26840
26853
|
maxLeverage: config.hedge.policy.maxLeverage
|
|
26841
26854
|
});
|
|
26842
26855
|
}
|
|
26843
|
-
const operator = new
|
|
26856
|
+
const operator = new PublicKey4(profile.operator);
|
|
26844
26857
|
const balance = BigInt(await this.maker.options.connection.getBalance(operator, "confirmed"));
|
|
26845
26858
|
const signatures = [];
|
|
26846
26859
|
const recovered = this.view(await this.authorizedRequest("fund", { revision: current.revision }));
|
|
@@ -26952,7 +26965,7 @@ async function queueAccounts(provider, connection, name, offset) {
|
|
|
26952
26965
|
import * as anchor2 from "@anchor-lang/core";
|
|
26953
26966
|
import { DEPTH_PROGRAM_ID as DEPTH_PROGRAM_ID2, SOL_USD_MARKET_ID } from "@depthhq/bindings";
|
|
26954
26967
|
import { DepthError } from "@depthhq/sdk";
|
|
26955
|
-
import { PublicKey as
|
|
26968
|
+
import { PublicKey as PublicKey5 } from "@solana/web3.js";
|
|
26956
26969
|
function u64(value, name) {
|
|
26957
26970
|
if (typeof value !== "bigint" || value < 0n || value > (1n << 64n) - 1n)
|
|
26958
26971
|
throw new RangeError(`${name} must be an unsigned 64-bit bigint`);
|
|
@@ -26969,7 +26982,7 @@ function timing(options) {
|
|
|
26969
26982
|
}
|
|
26970
26983
|
function address2(market, maker, nonce) {
|
|
26971
26984
|
const bytes = u64(nonce, "clientNonce").toArrayLike(Buffer, "le", 8);
|
|
26972
|
-
return
|
|
26985
|
+
return PublicKey5.findProgramAddressSync([Buffer.from("backstop"), market.toBuffer(), maker.toBuffer(), bytes], DEPTH_PROGRAM_ID2)[0];
|
|
26973
26986
|
}
|
|
26974
26987
|
async function poll(read2, terminal, options) {
|
|
26975
26988
|
const { timeoutMs, pollMs } = timing(options);
|
|
@@ -27011,7 +27024,7 @@ class BackstopHandle {
|
|
|
27011
27024
|
]);
|
|
27012
27025
|
const now = Math.floor(Date.now() / 1000);
|
|
27013
27026
|
const margin = (input.maxCapacity * BigInt(market.config.initialMarginBps) + 9999n) / 10000n;
|
|
27014
|
-
if (!market.backstopOffer.equals(
|
|
27027
|
+
if (!market.backstopOffer.equals(PublicKey5.default) || market.pendingOrders !== 0 || Object.keys(market.status)[0] === "settling" || input.maxCapacity > BigInt(market.config.maxAccountNotional.toString()) || margin < BigInt(market.config.backstopMinCollateral.toString()))
|
|
27015
27028
|
throw new Error("Backstop offer is outside the current market policy");
|
|
27016
27029
|
if (!account.owner.equals(client.options.maker) || !account.market.equals(client.marketAddress) || !("ready" in account.status))
|
|
27017
27030
|
throw new Error("Maker market account is unavailable");
|
|
@@ -27113,7 +27126,7 @@ class BackstopRelease {
|
|
|
27113
27126
|
|
|
27114
27127
|
// src/fill/history.ts
|
|
27115
27128
|
import * as anchor3 from "@anchor-lang/core";
|
|
27116
|
-
import { PublicKey as
|
|
27129
|
+
import { PublicKey as PublicKey6 } from "@solana/web3.js";
|
|
27117
27130
|
|
|
27118
27131
|
class FillHistory {
|
|
27119
27132
|
client;
|
|
@@ -27176,7 +27189,7 @@ class FillHistory {
|
|
|
27176
27189
|
const fills = [];
|
|
27177
27190
|
for (let i2 = 0;i2 < addresses.length; i2 += 100) {
|
|
27178
27191
|
const batch = addresses.slice(i2, i2 + 100);
|
|
27179
|
-
const accounts2 = await connection.getMultipleAccountsInfo(batch.map((id) => new
|
|
27192
|
+
const accounts2 = await connection.getMultipleAccountsInfo(batch.map((id) => new PublicKey6(id)), "finalized");
|
|
27180
27193
|
accounts2.forEach((info, index) => {
|
|
27181
27194
|
if (!info || !info.owner.equals(this.client.program.programId))
|
|
27182
27195
|
throw new Error("Finalized fill receipt is unavailable");
|
|
@@ -27321,7 +27334,7 @@ class QuoteHandle {
|
|
|
27321
27334
|
const market = await this.client.read("Market", this.client.marketAddress);
|
|
27322
27335
|
if (!Number.isSafeInteger(input.validForSeconds) || input.validForSeconds < 1 || input.validForSeconds > market.config.maxQuoteLifetimeSeconds)
|
|
27323
27336
|
throw new RangeError("Quote duration is outside market policy");
|
|
27324
|
-
const expiry =
|
|
27337
|
+
const expiry = await chainTime(this.client.options.connection) + input.validForSeconds;
|
|
27325
27338
|
const before = await this.status();
|
|
27326
27339
|
if (before.status !== "active")
|
|
27327
27340
|
throw new Error("Only active quotes can be renewed");
|
|
@@ -27587,7 +27600,7 @@ class QuoteHandle {
|
|
|
27587
27600
|
// src/quote/replacement.ts
|
|
27588
27601
|
import * as anchor5 from "@anchor-lang/core";
|
|
27589
27602
|
import { DEPTH_PROGRAM_ID as DEPTH_PROGRAM_ID3 } from "@depthhq/bindings";
|
|
27590
|
-
import { PublicKey as
|
|
27603
|
+
import { PublicKey as PublicKey7 } from "@solana/web3.js";
|
|
27591
27604
|
import { quoteBounds as quoteBounds3 } from "@depthhq/bindings";
|
|
27592
27605
|
|
|
27593
27606
|
class QuoteReplacement {
|
|
@@ -27603,7 +27616,7 @@ class QuoteReplacement {
|
|
|
27603
27616
|
throw new RangeError("clientNonce must be an unsigned 64-bit bigint");
|
|
27604
27617
|
}
|
|
27605
27618
|
const bytes = new anchor5.BN(nonce.toString()).toArrayLike(Buffer, "le", 8);
|
|
27606
|
-
this.nextId =
|
|
27619
|
+
this.nextId = PublicKey7.findProgramAddressSync([
|
|
27607
27620
|
Buffer.from("quote"),
|
|
27608
27621
|
client.marketAddress.toBuffer(),
|
|
27609
27622
|
client.options.maker.toBuffer(),
|
|
@@ -27786,7 +27799,7 @@ async function cleanupQuotes(client, options = {}) {
|
|
|
27786
27799
|
throw new RangeError("Cleanup limit must be between 1 and 12");
|
|
27787
27800
|
const excluded = new Set(options.exclude);
|
|
27788
27801
|
const actor = client.options.wallet.publicKey;
|
|
27789
|
-
const
|
|
27802
|
+
const owner2 = actor.equals(client.options.maker);
|
|
27790
27803
|
const transaction = new Transaction2().add(ComputeBudgetProgram.setComputeUnitLimit({ units: 400000 }));
|
|
27791
27804
|
let closed = 0;
|
|
27792
27805
|
let reclaimedLamports = 0n;
|
|
@@ -27797,7 +27810,7 @@ async function cleanupQuotes(client, options = {}) {
|
|
|
27797
27810
|
if (excluded.has(item.id.toBase58()))
|
|
27798
27811
|
continue;
|
|
27799
27812
|
const state = await client.quoteState(item.id);
|
|
27800
|
-
if (!["cancelled", "filled", "rejected"].includes(Object.keys(state.status)[0]) || state.attachedOrders !== 0 || !
|
|
27813
|
+
if (!["cancelled", "filled", "rejected"].includes(Object.keys(state.status)[0]) || state.attachedOrders !== 0 || !owner2 && !state.operator.equals(actor))
|
|
27801
27814
|
continue;
|
|
27802
27815
|
if (state.replacementNonce != null) {
|
|
27803
27816
|
const successor = client.quote.replacement(item.id, BigInt(state.replacementNonce.toString())).nextId;
|
|
@@ -27807,7 +27820,7 @@ async function cleanupQuotes(client, options = {}) {
|
|
|
27807
27820
|
const info = await client.options.connection.getAccountInfo(item.id, "confirmed");
|
|
27808
27821
|
if (!info)
|
|
27809
27822
|
continue;
|
|
27810
|
-
transaction.add(await (
|
|
27823
|
+
transaction.add(await (owner2 ? client.program.methods.closeQuote().accountsPartial({ maker: actor, quote: item.id }) : client.program.methods.closeOperatorQuote().accountsPartial({ operator: actor, quote: item.id })).instruction());
|
|
27811
27824
|
reclaimedLamports += BigInt(info.lamports);
|
|
27812
27825
|
if (++closed === limit)
|
|
27813
27826
|
break;
|
|
@@ -27824,7 +27837,7 @@ async function cleanupQuotes(client, options = {}) {
|
|
|
27824
27837
|
|
|
27825
27838
|
// src/client/client.ts
|
|
27826
27839
|
function pda(seeds) {
|
|
27827
|
-
return
|
|
27840
|
+
return PublicKey8.findProgramAddressSync(seeds, DEPTH_PROGRAM_ID4)[0];
|
|
27828
27841
|
}
|
|
27829
27842
|
function u642(value, name2) {
|
|
27830
27843
|
if (typeof value !== "bigint" || value < 0n || value > (1n << 64n) - 1n) {
|
|
@@ -27898,7 +27911,7 @@ class MakerClient {
|
|
|
27898
27911
|
this.backstop = Object.assign((id) => new BackstopHandle(id, this), { offer: (input) => BackstopHandle.offer(this, input) });
|
|
27899
27912
|
}
|
|
27900
27913
|
static async create(options) {
|
|
27901
|
-
const appId = typeof options.appId === "string" ? new
|
|
27914
|
+
const appId = typeof options.appId === "string" ? new PublicKey8(options.appId) : options.appId;
|
|
27902
27915
|
if (options.maker && options.makerOwner && !options.maker.equals(options.makerOwner)) {
|
|
27903
27916
|
throw new Error("maker and makerOwner identify different accounts");
|
|
27904
27917
|
}
|
|
@@ -27944,7 +27957,7 @@ class MakerClient {
|
|
|
27944
27957
|
summary: async () => (await this.owned()).account.summary(),
|
|
27945
27958
|
pending: async () => (await this.owned()).account.pending(),
|
|
27946
27959
|
deposit: async (sourceOrAmount, amount3, clientNonce) => {
|
|
27947
|
-
if (sourceOrAmount instanceof
|
|
27960
|
+
if (sourceOrAmount instanceof PublicKey8) {
|
|
27948
27961
|
if (amount3 === undefined || clientNonce === undefined)
|
|
27949
27962
|
throw new RangeError("Source deposits require amount and nonce");
|
|
27950
27963
|
return this.funding.deposit(sourceOrAmount, amount3, clientNonce);
|
|
@@ -27954,7 +27967,7 @@ class MakerClient {
|
|
|
27954
27967
|
withdrawalHandle: (clientNonce) => this.funding.withdrawalHandle(clientNonce),
|
|
27955
27968
|
depositHandle: (nonce) => this.funding.depositHandle(nonce),
|
|
27956
27969
|
withdraw: async (destinationOrAmount, amount3, clientNonce) => {
|
|
27957
|
-
if (destinationOrAmount instanceof
|
|
27970
|
+
if (destinationOrAmount instanceof PublicKey8) {
|
|
27958
27971
|
if (amount3 === undefined || clientNonce === undefined)
|
|
27959
27972
|
throw new RangeError("Destination withdrawals require amount and nonce");
|
|
27960
27973
|
return this.funding.withdraw(destinationOrAmount, amount3, clientNonce);
|
|
@@ -28104,8 +28117,9 @@ class MakerClient {
|
|
|
28104
28117
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
28105
28118
|
}
|
|
28106
28119
|
const market = await this.read("Market", this.marketAddress);
|
|
28107
|
-
const
|
|
28108
|
-
this.
|
|
28120
|
+
const time = await chainTime(this.options.connection);
|
|
28121
|
+
const input = "tiers" in request ? request : this.flatQuote(request, market, clientNonce, time);
|
|
28122
|
+
this.validateQuote(input, market, time);
|
|
28109
28123
|
const grant = await this.grantFor(input.maxCapacity, input.expiresAt);
|
|
28110
28124
|
const mxePublicKey = await getMXEPublicKey(this.provider, DEPTH_PROGRAM_ID4);
|
|
28111
28125
|
if (!mxePublicKey)
|
|
@@ -28147,7 +28161,7 @@ class MakerClient {
|
|
|
28147
28161
|
const limit = options.limit ?? 20;
|
|
28148
28162
|
if (!Number.isSafeInteger(limit) || limit < 1 || limit > 100)
|
|
28149
28163
|
throw new RangeError("limit must be an integer from 1 to 100");
|
|
28150
|
-
const cursor = options.cursor ? new
|
|
28164
|
+
const cursor = options.cursor ? new PublicKey8(options.cursor).toBase58() : undefined;
|
|
28151
28165
|
const accounts2 = await this.options.connection.getProgramAccounts(DEPTH_PROGRAM_ID4, {
|
|
28152
28166
|
commitment: "confirmed",
|
|
28153
28167
|
dataSlice: { offset: 0, length: 0 },
|
|
@@ -28213,7 +28227,7 @@ class MakerClient {
|
|
|
28213
28227
|
return this.quote.replacement(prior, nonce).resume(input, options);
|
|
28214
28228
|
}
|
|
28215
28229
|
};
|
|
28216
|
-
flatQuote(input, market, clientNonce) {
|
|
28230
|
+
flatQuote(input, market, clientNonce, now) {
|
|
28217
28231
|
if (input.marketId !== SOL_USD_MARKET_ID2)
|
|
28218
28232
|
throw new Error("Only SOL-USD is supported");
|
|
28219
28233
|
if (!Number.isSafeInteger(input.validForSeconds) || input.validForSeconds < 1 || input.validForSeconds > market.config.maxQuoteLifetimeSeconds)
|
|
@@ -28228,7 +28242,7 @@ class MakerClient {
|
|
|
28228
28242
|
return {
|
|
28229
28243
|
tiers,
|
|
28230
28244
|
maxCapacity: input.maxCapacity,
|
|
28231
|
-
expiresAt:
|
|
28245
|
+
expiresAt: now + input.validForSeconds,
|
|
28232
28246
|
clientNonce
|
|
28233
28247
|
};
|
|
28234
28248
|
}
|
|
@@ -28351,7 +28365,7 @@ class MakerClient {
|
|
|
28351
28365
|
const store = createCursorStore(genesis, this.options.maker.toBase58(), this.options.cursorDirectory);
|
|
28352
28366
|
const cursor = await store.load();
|
|
28353
28367
|
return new FillHistory(this).subscribe(async (fill) => {
|
|
28354
|
-
const execution = await this.fills.get(new
|
|
28368
|
+
const execution = await this.fills.get(new PublicKey8(fill.id));
|
|
28355
28369
|
if (execution.status !== "ready")
|
|
28356
28370
|
throw new Error(`Private maker fill ${fill.id} is ${execution.status}`);
|
|
28357
28371
|
await options.onFill({ ...fill, execution });
|
|
@@ -28370,8 +28384,7 @@ class MakerClient {
|
|
|
28370
28384
|
return result;
|
|
28371
28385
|
}
|
|
28372
28386
|
};
|
|
28373
|
-
validateQuote(input, market) {
|
|
28374
|
-
const now = Math.floor(Date.now() / 1000);
|
|
28387
|
+
validateQuote(input, market, now) {
|
|
28375
28388
|
const reference = BigInt(market.oraclePriceE8.toString());
|
|
28376
28389
|
const { preparationBps } = quoteBounds4(market.config.maxQuoteDeviationBps);
|
|
28377
28390
|
if (!["draft", "active"].includes(stateName(market.status)))
|
package/dist/index.node.js
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
// src/client/client.ts
|
|
2
2
|
import { Buffer as Buffer8 } from "buffer";
|
|
3
|
+
|
|
4
|
+
// src/chain/clock.ts
|
|
5
|
+
import { PublicKey, SYSVAR_CLOCK_PUBKEY } from "@solana/web3.js";
|
|
6
|
+
var owner = new PublicKey("Sysvar1111111111111111111111111111111111111");
|
|
7
|
+
async function chainTime(connection) {
|
|
8
|
+
const clock = await connection.getAccountInfo(SYSVAR_CLOCK_PUBKEY, "confirmed");
|
|
9
|
+
if (!clock?.owner.equals(owner) || clock.data.length !== 40)
|
|
10
|
+
throw new Error("Solana clock sysvar is unavailable");
|
|
11
|
+
const time = clock.data.readBigInt64LE(32);
|
|
12
|
+
if (time <= 0n || time > BigInt(Number.MAX_SAFE_INTEGER))
|
|
13
|
+
throw new Error("Solana clock timestamp is invalid");
|
|
14
|
+
return Number(time);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// src/client/client.ts
|
|
3
18
|
import * as anchor6 from "@anchor-lang/core";
|
|
4
19
|
|
|
5
20
|
// ../../node_modules/@arcium-hq/client/build/index.mjs
|
|
@@ -2233,7 +2248,7 @@ import * as anchor from "@anchor-lang/core";
|
|
|
2233
2248
|
import { Buffer } from "buffer";
|
|
2234
2249
|
import * as anchor__default from "@anchor-lang/core";
|
|
2235
2250
|
import { BorshCoder, convertIdlToCamelCase, Program } from "@anchor-lang/core";
|
|
2236
|
-
import { AddressLookupTableProgram, PublicKey } from "@solana/web3.js";
|
|
2251
|
+
import { AddressLookupTableProgram, PublicKey as PublicKey2 } from "@solana/web3.js";
|
|
2237
2252
|
var CURVE25519_SCALAR_FIELD_MODULUS = ed25519.CURVE.n;
|
|
2238
2253
|
function serializeLE(val, lengthInBytes) {
|
|
2239
2254
|
const result = new Uint8Array(lengthInBytes);
|
|
@@ -24840,7 +24855,7 @@ function findArciumPda(seeds) {
|
|
|
24840
24855
|
return findPda(getArciumProgramId(), seeds);
|
|
24841
24856
|
}
|
|
24842
24857
|
function findPda(programId, seeds) {
|
|
24843
|
-
return
|
|
24858
|
+
return PublicKey2.findProgramAddressSync(seeds, programId)[0];
|
|
24844
24859
|
}
|
|
24845
24860
|
function assertIntegerInRange(value, min, max, label) {
|
|
24846
24861
|
if (!Number.isInteger(value) || value < min || value > max) {
|
|
@@ -24912,7 +24927,7 @@ import {
|
|
|
24912
24927
|
} from "@depthhq/bindings";
|
|
24913
24928
|
import { DepthView } from "@depthhq/sdk/views";
|
|
24914
24929
|
import { DepthRecovery } from "@depthhq/sdk/recovery";
|
|
24915
|
-
import { PublicKey as
|
|
24930
|
+
import { PublicKey as PublicKey8 } from "@solana/web3.js";
|
|
24916
24931
|
|
|
24917
24932
|
// src/chain/random.ts
|
|
24918
24933
|
function randomBytes3(length) {
|
|
@@ -24935,8 +24950,8 @@ function order(value, receipt = false) {
|
|
|
24935
24950
|
return true;
|
|
24936
24951
|
return ["filled", "cancelled", "rejected"].includes(String(value.status)) && integer(value.completedAt) && value.completedAt >= value.nonce && amount(value.filledSize) && BigInt(value.filledSize) >= 0n && BigInt(value.filledSize) <= BigInt(value.size) && (value.filledAt === undefined || integer(value.filledAt) && value.filledAt >= value.nonce - 1000 && value.filledAt <= value.completedAt + 1000) && optional(value.orderId, integer) && optional(value.averagePriceE8, amount) && optional(value.fee, amount) && optional(value.reason, text) && optional(value.hashes, (hashes) => Array.isArray(hashes) && hashes.length <= 2000 && hashes.every((hash) => typeof hash === "string" && /^0x[0-9a-fA-F]{64}$/.test(hash)));
|
|
24937
24952
|
}
|
|
24938
|
-
function hedgeView(value,
|
|
24939
|
-
if (!object(value) || value.maker !==
|
|
24953
|
+
function hedgeView(value, owner2) {
|
|
24954
|
+
if (!object(value) || value.maker !== owner2 || typeof value.enabled !== "boolean")
|
|
24940
24955
|
throw new Error("Maker hedge response belongs to another wallet or is invalid");
|
|
24941
24956
|
const snapshot = value.snapshot;
|
|
24942
24957
|
if (snapshot !== null && (!value.enabled || !object(snapshot) || snapshot.venue !== "hyperliquid" || !["testnet", "mainnet"].includes(String(snapshot.network)) || typeof snapshot.account !== "string" || !/^0x[0-9a-fA-F]{40}$/.test(snapshot.account) || !integer(snapshot.updatedAt) || !["balanced", "waiting", "pending", "blocked"].includes(String(snapshot.phase)) || !optional(snapshot.reason, text) || !optional(snapshot.depthPosition, amount) || !optional(snapshot.externalPosition, amount) || !optional(snapshot.unhedgedPosition, amount) || !optional(snapshot.pending, order) || !Array.isArray(snapshot.history) || snapshot.history.length > 50 || !snapshot.history.every((record) => order(record, true))))
|
|
@@ -25027,7 +25042,7 @@ class MakerAccess extends WalletSession {
|
|
|
25027
25042
|
}
|
|
25028
25043
|
|
|
25029
25044
|
// src/automation/automation.ts
|
|
25030
|
-
import { PublicKey as
|
|
25045
|
+
import { PublicKey as PublicKey4, SystemProgram, Transaction } from "@solana/web3.js";
|
|
25031
25046
|
import { Buffer as Buffer3 } from "buffer";
|
|
25032
25047
|
|
|
25033
25048
|
// src/hedge/setup.ts
|
|
@@ -25115,7 +25130,7 @@ async function setup_hyperliquid(options) {
|
|
|
25115
25130
|
}
|
|
25116
25131
|
|
|
25117
25132
|
// src/automation/types.ts
|
|
25118
|
-
import { PublicKey as
|
|
25133
|
+
import { PublicKey as PublicKey3 } from "@solana/web3.js";
|
|
25119
25134
|
|
|
25120
25135
|
// src/bot/policy.ts
|
|
25121
25136
|
import { positionPnl } from "@depthhq/sdk";
|
|
@@ -25248,7 +25263,7 @@ function automationConfig(value) {
|
|
|
25248
25263
|
};
|
|
25249
25264
|
}
|
|
25250
25265
|
var automationWire = (config) => JSON.parse(JSON.stringify(config, (_key, value) => typeof value === "bigint" ? value.toString() : value));
|
|
25251
|
-
function automationView(value,
|
|
25266
|
+
function automationView(value, owner2, environment) {
|
|
25252
25267
|
if (value === null)
|
|
25253
25268
|
return null;
|
|
25254
25269
|
const view = object2(value, [
|
|
@@ -25266,9 +25281,9 @@ function automationView(value, owner, environment) {
|
|
|
25266
25281
|
"hedge",
|
|
25267
25282
|
"funding"
|
|
25268
25283
|
]);
|
|
25269
|
-
if (view.owner !==
|
|
25284
|
+
if (view.owner !== owner2 || view.environment !== environment)
|
|
25270
25285
|
throw new Error("Automation belongs to another wallet or network");
|
|
25271
|
-
if (typeof view.operator !== "string" || new
|
|
25286
|
+
if (typeof view.operator !== "string" || new PublicKey3(view.operator).toBase58() !== view.operator || typeof view.agent !== "string" || !/^0x[0-9a-fA-F]{40}$/.test(view.agent) || integer2(view.revision) < 1 || integer2(view.updatedAt) < 1 || !["running", "paused"].includes(String(view.desired)) || ![
|
|
25272
25287
|
"configured",
|
|
25273
25288
|
"starting",
|
|
25274
25289
|
"running",
|
|
@@ -25280,10 +25295,10 @@ function automationView(value, owner, environment) {
|
|
|
25280
25295
|
automationConfig(view.config);
|
|
25281
25296
|
if (view.bot !== undefined) {
|
|
25282
25297
|
const bot = object2(view.bot, ["phase", "reason", "quoteId", "fillCount"]);
|
|
25283
|
-
if (!["active", "pending", "idle", "stopped"].includes(String(bot.phase)) || integer2(bot.fillCount) < 0 || bot.reason !== undefined && typeof bot.reason !== "string" || bot.quoteId !== undefined && (typeof bot.quoteId !== "string" || new
|
|
25298
|
+
if (!["active", "pending", "idle", "stopped"].includes(String(bot.phase)) || integer2(bot.fillCount) < 0 || bot.reason !== undefined && typeof bot.reason !== "string" || bot.quoteId !== undefined && (typeof bot.quoteId !== "string" || new PublicKey3(bot.quoteId).toBase58() !== bot.quoteId))
|
|
25284
25299
|
throw new Error("Automation status is invalid");
|
|
25285
25300
|
}
|
|
25286
|
-
hedgeView(view.hedge,
|
|
25301
|
+
hedgeView(view.hedge, owner2);
|
|
25287
25302
|
if (view.funding !== undefined) {
|
|
25288
25303
|
const funding = object2(view.funding, ["signature", "lamports", "status"]);
|
|
25289
25304
|
if (typeof funding.signature !== "string" || !/^[1-9A-HJ-NP-Za-km-z]{64,90}$/.test(funding.signature) || !["pending", "confirmed", "expired", "failed"].includes(String(funding.status)))
|
|
@@ -25355,7 +25370,7 @@ class MakerAutomation extends WalletSession {
|
|
|
25355
25370
|
maxLeverage: config.hedge.policy.maxLeverage
|
|
25356
25371
|
});
|
|
25357
25372
|
}
|
|
25358
|
-
const operator = new
|
|
25373
|
+
const operator = new PublicKey4(profile.operator);
|
|
25359
25374
|
const balance = BigInt(await this.maker.options.connection.getBalance(operator, "confirmed"));
|
|
25360
25375
|
const signatures = [];
|
|
25361
25376
|
const recovered = this.view(await this.authorizedRequest("fund", { revision: current.revision }));
|
|
@@ -25469,7 +25484,7 @@ import { Buffer as Buffer5 } from "buffer";
|
|
|
25469
25484
|
import * as anchor2 from "@anchor-lang/core";
|
|
25470
25485
|
import { DEPTH_PROGRAM_ID as DEPTH_PROGRAM_ID2, SOL_USD_MARKET_ID } from "@depthhq/bindings";
|
|
25471
25486
|
import { DepthError } from "@depthhq/sdk";
|
|
25472
|
-
import { PublicKey as
|
|
25487
|
+
import { PublicKey as PublicKey5 } from "@solana/web3.js";
|
|
25473
25488
|
function u64(value, name) {
|
|
25474
25489
|
if (typeof value !== "bigint" || value < 0n || value > (1n << 64n) - 1n)
|
|
25475
25490
|
throw new RangeError(`${name} must be an unsigned 64-bit bigint`);
|
|
@@ -25486,7 +25501,7 @@ function timing(options) {
|
|
|
25486
25501
|
}
|
|
25487
25502
|
function address2(market, maker, nonce) {
|
|
25488
25503
|
const bytes = u64(nonce, "clientNonce").toArrayLike(Buffer5, "le", 8);
|
|
25489
|
-
return
|
|
25504
|
+
return PublicKey5.findProgramAddressSync([Buffer5.from("backstop"), market.toBuffer(), maker.toBuffer(), bytes], DEPTH_PROGRAM_ID2)[0];
|
|
25490
25505
|
}
|
|
25491
25506
|
async function poll(read, terminal, options) {
|
|
25492
25507
|
const { timeoutMs, pollMs } = timing(options);
|
|
@@ -25528,7 +25543,7 @@ class BackstopHandle {
|
|
|
25528
25543
|
]);
|
|
25529
25544
|
const now = Math.floor(Date.now() / 1000);
|
|
25530
25545
|
const margin = (input.maxCapacity * BigInt(market.config.initialMarginBps) + 9999n) / 10000n;
|
|
25531
|
-
if (!market.backstopOffer.equals(
|
|
25546
|
+
if (!market.backstopOffer.equals(PublicKey5.default) || market.pendingOrders !== 0 || Object.keys(market.status)[0] === "settling" || input.maxCapacity > BigInt(market.config.maxAccountNotional.toString()) || margin < BigInt(market.config.backstopMinCollateral.toString()))
|
|
25532
25547
|
throw new Error("Backstop offer is outside the current market policy");
|
|
25533
25548
|
if (!account.owner.equals(client.options.maker) || !account.market.equals(client.marketAddress) || !("ready" in account.status))
|
|
25534
25549
|
throw new Error("Maker market account is unavailable");
|
|
@@ -25631,7 +25646,7 @@ class BackstopRelease {
|
|
|
25631
25646
|
// src/fill/history.ts
|
|
25632
25647
|
import { Buffer as Buffer6 } from "buffer";
|
|
25633
25648
|
import * as anchor3 from "@anchor-lang/core";
|
|
25634
|
-
import { PublicKey as
|
|
25649
|
+
import { PublicKey as PublicKey6 } from "@solana/web3.js";
|
|
25635
25650
|
|
|
25636
25651
|
class FillHistory {
|
|
25637
25652
|
client;
|
|
@@ -25694,7 +25709,7 @@ class FillHistory {
|
|
|
25694
25709
|
const fills = [];
|
|
25695
25710
|
for (let i = 0;i < addresses.length; i += 100) {
|
|
25696
25711
|
const batch = addresses.slice(i, i + 100);
|
|
25697
|
-
const accounts2 = await connection.getMultipleAccountsInfo(batch.map((id) => new
|
|
25712
|
+
const accounts2 = await connection.getMultipleAccountsInfo(batch.map((id) => new PublicKey6(id)), "finalized");
|
|
25698
25713
|
accounts2.forEach((info, index) => {
|
|
25699
25714
|
if (!info || !info.owner.equals(this.client.program.programId))
|
|
25700
25715
|
throw new Error("Finalized fill receipt is unavailable");
|
|
@@ -25840,7 +25855,7 @@ class QuoteHandle {
|
|
|
25840
25855
|
const market = await this.client.read("Market", this.client.marketAddress);
|
|
25841
25856
|
if (!Number.isSafeInteger(input.validForSeconds) || input.validForSeconds < 1 || input.validForSeconds > market.config.maxQuoteLifetimeSeconds)
|
|
25842
25857
|
throw new RangeError("Quote duration is outside market policy");
|
|
25843
|
-
const expiry =
|
|
25858
|
+
const expiry = await chainTime(this.client.options.connection) + input.validForSeconds;
|
|
25844
25859
|
const before = await this.status();
|
|
25845
25860
|
if (before.status !== "active")
|
|
25846
25861
|
throw new Error("Only active quotes can be renewed");
|
|
@@ -26106,7 +26121,7 @@ class QuoteHandle {
|
|
|
26106
26121
|
// src/quote/replacement.ts
|
|
26107
26122
|
import * as anchor5 from "@anchor-lang/core";
|
|
26108
26123
|
import { DEPTH_PROGRAM_ID as DEPTH_PROGRAM_ID3 } from "@depthhq/bindings";
|
|
26109
|
-
import { PublicKey as
|
|
26124
|
+
import { PublicKey as PublicKey7 } from "@solana/web3.js";
|
|
26110
26125
|
import { Buffer as Buffer7 } from "buffer";
|
|
26111
26126
|
import { quoteBounds as quoteBounds3 } from "@depthhq/bindings";
|
|
26112
26127
|
|
|
@@ -26123,7 +26138,7 @@ class QuoteReplacement {
|
|
|
26123
26138
|
throw new RangeError("clientNonce must be an unsigned 64-bit bigint");
|
|
26124
26139
|
}
|
|
26125
26140
|
const bytes = new anchor5.BN(nonce.toString()).toArrayLike(Buffer7, "le", 8);
|
|
26126
|
-
this.nextId =
|
|
26141
|
+
this.nextId = PublicKey7.findProgramAddressSync([
|
|
26127
26142
|
Buffer7.from("quote"),
|
|
26128
26143
|
client.marketAddress.toBuffer(),
|
|
26129
26144
|
client.options.maker.toBuffer(),
|
|
@@ -26306,7 +26321,7 @@ async function cleanupQuotes(client, options = {}) {
|
|
|
26306
26321
|
throw new RangeError("Cleanup limit must be between 1 and 12");
|
|
26307
26322
|
const excluded = new Set(options.exclude);
|
|
26308
26323
|
const actor = client.options.wallet.publicKey;
|
|
26309
|
-
const
|
|
26324
|
+
const owner2 = actor.equals(client.options.maker);
|
|
26310
26325
|
const transaction = new Transaction2().add(ComputeBudgetProgram.setComputeUnitLimit({ units: 400000 }));
|
|
26311
26326
|
let closed = 0;
|
|
26312
26327
|
let reclaimedLamports = 0n;
|
|
@@ -26317,7 +26332,7 @@ async function cleanupQuotes(client, options = {}) {
|
|
|
26317
26332
|
if (excluded.has(item.id.toBase58()))
|
|
26318
26333
|
continue;
|
|
26319
26334
|
const state = await client.quoteState(item.id);
|
|
26320
|
-
if (!["cancelled", "filled", "rejected"].includes(Object.keys(state.status)[0]) || state.attachedOrders !== 0 || !
|
|
26335
|
+
if (!["cancelled", "filled", "rejected"].includes(Object.keys(state.status)[0]) || state.attachedOrders !== 0 || !owner2 && !state.operator.equals(actor))
|
|
26321
26336
|
continue;
|
|
26322
26337
|
if (state.replacementNonce != null) {
|
|
26323
26338
|
const successor = client.quote.replacement(item.id, BigInt(state.replacementNonce.toString())).nextId;
|
|
@@ -26327,7 +26342,7 @@ async function cleanupQuotes(client, options = {}) {
|
|
|
26327
26342
|
const info = await client.options.connection.getAccountInfo(item.id, "confirmed");
|
|
26328
26343
|
if (!info)
|
|
26329
26344
|
continue;
|
|
26330
|
-
transaction.add(await (
|
|
26345
|
+
transaction.add(await (owner2 ? client.program.methods.closeQuote().accountsPartial({ maker: actor, quote: item.id }) : client.program.methods.closeOperatorQuote().accountsPartial({ operator: actor, quote: item.id })).instruction());
|
|
26331
26346
|
reclaimedLamports += BigInt(info.lamports);
|
|
26332
26347
|
if (++closed === limit)
|
|
26333
26348
|
break;
|
|
@@ -26344,7 +26359,7 @@ async function cleanupQuotes(client, options = {}) {
|
|
|
26344
26359
|
|
|
26345
26360
|
// src/client/client.ts
|
|
26346
26361
|
function pda(seeds) {
|
|
26347
|
-
return
|
|
26362
|
+
return PublicKey8.findProgramAddressSync(seeds, DEPTH_PROGRAM_ID4)[0];
|
|
26348
26363
|
}
|
|
26349
26364
|
function u642(value, name2) {
|
|
26350
26365
|
if (typeof value !== "bigint" || value < 0n || value > (1n << 64n) - 1n) {
|
|
@@ -26418,7 +26433,7 @@ class MakerClient {
|
|
|
26418
26433
|
this.backstop = Object.assign((id) => new BackstopHandle(id, this), { offer: (input) => BackstopHandle.offer(this, input) });
|
|
26419
26434
|
}
|
|
26420
26435
|
static async create(options) {
|
|
26421
|
-
const appId = typeof options.appId === "string" ? new
|
|
26436
|
+
const appId = typeof options.appId === "string" ? new PublicKey8(options.appId) : options.appId;
|
|
26422
26437
|
if (options.maker && options.makerOwner && !options.maker.equals(options.makerOwner)) {
|
|
26423
26438
|
throw new Error("maker and makerOwner identify different accounts");
|
|
26424
26439
|
}
|
|
@@ -26464,7 +26479,7 @@ class MakerClient {
|
|
|
26464
26479
|
summary: async () => (await this.owned()).account.summary(),
|
|
26465
26480
|
pending: async () => (await this.owned()).account.pending(),
|
|
26466
26481
|
deposit: async (sourceOrAmount, amount3, clientNonce) => {
|
|
26467
|
-
if (sourceOrAmount instanceof
|
|
26482
|
+
if (sourceOrAmount instanceof PublicKey8) {
|
|
26468
26483
|
if (amount3 === undefined || clientNonce === undefined)
|
|
26469
26484
|
throw new RangeError("Source deposits require amount and nonce");
|
|
26470
26485
|
return this.funding.deposit(sourceOrAmount, amount3, clientNonce);
|
|
@@ -26474,7 +26489,7 @@ class MakerClient {
|
|
|
26474
26489
|
withdrawalHandle: (clientNonce) => this.funding.withdrawalHandle(clientNonce),
|
|
26475
26490
|
depositHandle: (nonce) => this.funding.depositHandle(nonce),
|
|
26476
26491
|
withdraw: async (destinationOrAmount, amount3, clientNonce) => {
|
|
26477
|
-
if (destinationOrAmount instanceof
|
|
26492
|
+
if (destinationOrAmount instanceof PublicKey8) {
|
|
26478
26493
|
if (amount3 === undefined || clientNonce === undefined)
|
|
26479
26494
|
throw new RangeError("Destination withdrawals require amount and nonce");
|
|
26480
26495
|
return this.funding.withdraw(destinationOrAmount, amount3, clientNonce);
|
|
@@ -26624,8 +26639,9 @@ class MakerClient {
|
|
|
26624
26639
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
26625
26640
|
}
|
|
26626
26641
|
const market = await this.read("Market", this.marketAddress);
|
|
26627
|
-
const
|
|
26628
|
-
this.
|
|
26642
|
+
const time = await chainTime(this.options.connection);
|
|
26643
|
+
const input = "tiers" in request ? request : this.flatQuote(request, market, clientNonce, time);
|
|
26644
|
+
this.validateQuote(input, market, time);
|
|
26629
26645
|
const grant = await this.grantFor(input.maxCapacity, input.expiresAt);
|
|
26630
26646
|
const mxePublicKey = await getMXEPublicKey(this.provider, DEPTH_PROGRAM_ID4);
|
|
26631
26647
|
if (!mxePublicKey)
|
|
@@ -26667,7 +26683,7 @@ class MakerClient {
|
|
|
26667
26683
|
const limit = options.limit ?? 20;
|
|
26668
26684
|
if (!Number.isSafeInteger(limit) || limit < 1 || limit > 100)
|
|
26669
26685
|
throw new RangeError("limit must be an integer from 1 to 100");
|
|
26670
|
-
const cursor = options.cursor ? new
|
|
26686
|
+
const cursor = options.cursor ? new PublicKey8(options.cursor).toBase58() : undefined;
|
|
26671
26687
|
const accounts2 = await this.options.connection.getProgramAccounts(DEPTH_PROGRAM_ID4, {
|
|
26672
26688
|
commitment: "confirmed",
|
|
26673
26689
|
dataSlice: { offset: 0, length: 0 },
|
|
@@ -26733,7 +26749,7 @@ class MakerClient {
|
|
|
26733
26749
|
return this.quote.replacement(prior, nonce).resume(input, options);
|
|
26734
26750
|
}
|
|
26735
26751
|
};
|
|
26736
|
-
flatQuote(input, market, clientNonce) {
|
|
26752
|
+
flatQuote(input, market, clientNonce, now) {
|
|
26737
26753
|
if (input.marketId !== SOL_USD_MARKET_ID2)
|
|
26738
26754
|
throw new Error("Only SOL-USD is supported");
|
|
26739
26755
|
if (!Number.isSafeInteger(input.validForSeconds) || input.validForSeconds < 1 || input.validForSeconds > market.config.maxQuoteLifetimeSeconds)
|
|
@@ -26748,7 +26764,7 @@ class MakerClient {
|
|
|
26748
26764
|
return {
|
|
26749
26765
|
tiers,
|
|
26750
26766
|
maxCapacity: input.maxCapacity,
|
|
26751
|
-
expiresAt:
|
|
26767
|
+
expiresAt: now + input.validForSeconds,
|
|
26752
26768
|
clientNonce
|
|
26753
26769
|
};
|
|
26754
26770
|
}
|
|
@@ -26871,7 +26887,7 @@ class MakerClient {
|
|
|
26871
26887
|
const store = createCursorStore(genesis, this.options.maker.toBase58(), this.options.cursorDirectory);
|
|
26872
26888
|
const cursor = await store.load();
|
|
26873
26889
|
return new FillHistory(this).subscribe(async (fill) => {
|
|
26874
|
-
const execution = await this.fills.get(new
|
|
26890
|
+
const execution = await this.fills.get(new PublicKey8(fill.id));
|
|
26875
26891
|
if (execution.status !== "ready")
|
|
26876
26892
|
throw new Error(`Private maker fill ${fill.id} is ${execution.status}`);
|
|
26877
26893
|
await options.onFill({ ...fill, execution });
|
|
@@ -26890,8 +26906,7 @@ class MakerClient {
|
|
|
26890
26906
|
return result;
|
|
26891
26907
|
}
|
|
26892
26908
|
};
|
|
26893
|
-
validateQuote(input, market) {
|
|
26894
|
-
const now = Math.floor(Date.now() / 1000);
|
|
26909
|
+
validateQuote(input, market, now) {
|
|
26895
26910
|
const reference = BigInt(market.oraclePriceE8.toString());
|
|
26896
26911
|
const { preparationBps } = quoteBounds4(market.config.maxQuoteDeviationBps);
|
|
26897
26912
|
if (!["draft", "active"].includes(stateName(market.status)))
|
package/dist/node.js
CHANGED
|
@@ -44,7 +44,7 @@ class FillCursorStore {
|
|
|
44
44
|
}
|
|
45
45
|
// src/bot/bot.ts
|
|
46
46
|
import { createHash, randomBytes as randomBytes3 } from "node:crypto";
|
|
47
|
-
import { PublicKey } from "@solana/web3.js";
|
|
47
|
+
import { PublicKey as PublicKey2 } from "@solana/web3.js";
|
|
48
48
|
import { DEPTH_PROGRAM_ID } from "@depthhq/bindings";
|
|
49
49
|
|
|
50
50
|
// src/bot/store.ts
|
|
@@ -372,6 +372,19 @@ function botQuote(policy, market, position, nonce, now, pricing, reservationCred
|
|
|
372
372
|
};
|
|
373
373
|
}
|
|
374
374
|
|
|
375
|
+
// src/chain/clock.ts
|
|
376
|
+
import { PublicKey, SYSVAR_CLOCK_PUBKEY } from "@solana/web3.js";
|
|
377
|
+
var owner = new PublicKey("Sysvar1111111111111111111111111111111111111");
|
|
378
|
+
async function chainTime(connection) {
|
|
379
|
+
const clock = await connection.getAccountInfo(SYSVAR_CLOCK_PUBKEY, "confirmed");
|
|
380
|
+
if (!clock?.owner.equals(owner) || clock.data.length !== 40)
|
|
381
|
+
throw new Error("Solana clock sysvar is unavailable");
|
|
382
|
+
const time = clock.data.readBigInt64LE(32);
|
|
383
|
+
if (time <= 0n || time > BigInt(Number.MAX_SAFE_INTEGER))
|
|
384
|
+
throw new Error("Solana clock timestamp is invalid");
|
|
385
|
+
return Number(time);
|
|
386
|
+
}
|
|
387
|
+
|
|
375
388
|
// src/bot/bot.ts
|
|
376
389
|
var terminal = new Set(["filled", "cancelled", "rejected"]);
|
|
377
390
|
var nonce = () => BigInt(`0x${randomBytes3(8).toString("hex")}`);
|
|
@@ -413,7 +426,7 @@ class MakerBot {
|
|
|
413
426
|
if (options.hedge) {
|
|
414
427
|
if (bot.state.hedge && bot.state.hedge.identity !== options.hedge.adapter.identity)
|
|
415
428
|
throw new Error("Hedge checkpoint belongs to another account or network");
|
|
416
|
-
bot.hedgeLease = new BotStore(
|
|
429
|
+
bot.hedgeLease = new BotStore(PublicKey2.default.toBase58(), new PublicKey2(createHash("sha256").update(options.hedge.adapter.identity).digest()).toBase58(), PublicKey2.default.toBase58(), options.stateDirectory);
|
|
417
430
|
await bot.hedgeLease.acquire();
|
|
418
431
|
const shared = await bot.hedgeLease.load();
|
|
419
432
|
if (shared.hedge)
|
|
@@ -463,18 +476,18 @@ class MakerBot {
|
|
|
463
476
|
const ids = [
|
|
464
477
|
this.state.quote,
|
|
465
478
|
write?.quote,
|
|
466
|
-
this.state.replacement ? this.maker.quote.replacement(new
|
|
479
|
+
this.state.replacement ? this.maker.quote.replacement(new PublicKey2(this.state.replacement.prior), this.state.replacement.nonce).nextId.toBase58() : undefined
|
|
467
480
|
];
|
|
468
481
|
for (const id of new Set(ids.filter((id2) => Boolean(id2)))) {
|
|
469
|
-
const quote = await this.maker.quoteState(new
|
|
470
|
-
if ((("reserving" in quote.status) || ("releasing" in quote.status)) && quote.pendingComputation?.equals(confirmed.pendingComputation ??
|
|
482
|
+
const quote = await this.maker.quoteState(new PublicKey2(id));
|
|
483
|
+
if ((("reserving" in quote.status) || ("releasing" in quote.status)) && quote.pendingComputation?.equals(confirmed.pendingComputation ?? PublicKey2.default))
|
|
471
484
|
return "updating quote margin";
|
|
472
485
|
}
|
|
473
486
|
}
|
|
474
487
|
let ready = "ready" in account.status && "ready" in confirmed.status && account.version.toString() === confirmed.version.toString();
|
|
475
488
|
const currentVersion = BigInt(confirmed.version.toString());
|
|
476
489
|
const candidate = write && this.position && "ready" in confirmed.status && currentVersion === write.version + 1n && (this.inventoryVersion ?? this.position.version) >= write.version && (this.inventoryVersion ?? this.position.version) <= currentVersion;
|
|
477
|
-
const completedQuote = write && "ready" in confirmed.status && currentVersion === write.version + 1n && await this.maker.quoteState(new
|
|
490
|
+
const completedQuote = write && "ready" in confirmed.status && currentVersion === write.version + 1n && await this.maker.quoteState(new PublicKey2(write.quote));
|
|
478
491
|
const completedWrite = candidate && completedQuote ? completedQuote.status : undefined;
|
|
479
492
|
const ownCommit = write && completedWrite && (write.release ? "cancelled" in completedWrite || "filled" in completedWrite : ("active" in completedWrite));
|
|
480
493
|
const riskWrite = [
|
|
@@ -535,7 +548,7 @@ class MakerBot {
|
|
|
535
548
|
const market = await this.maker.read("Market", this.maker.marketAddress);
|
|
536
549
|
const price = BigInt(market.oraclePriceE8.toString());
|
|
537
550
|
const expected = risk.externalPosition + this.state.hedge.history.filter((fill) => fill.nonce > risk.hedgeNonce).reduce((total, fill) => total + (fill.buy ? fill.filledSize : -fill.filledSize), 0n);
|
|
538
|
-
const quote = await this.maker.quoteState(new
|
|
551
|
+
const quote = await this.maker.quoteState(new PublicKey2(risk.quote));
|
|
539
552
|
const balanceNonce = Buffer.from(quote.balanceNonce).toString("hex");
|
|
540
553
|
const unchanged = currentVersion === risk.version;
|
|
541
554
|
const ownFill = "ready" in confirmed.status && currentVersion === risk.version + 1n && risk.balanceNonce !== undefined && balanceNonce !== risk.balanceNonce;
|
|
@@ -609,7 +622,7 @@ class MakerBot {
|
|
|
609
622
|
return;
|
|
610
623
|
const bytes = Buffer.alloc(8);
|
|
611
624
|
bytes.writeBigUInt64LE(value);
|
|
612
|
-
return
|
|
625
|
+
return PublicKey2.findProgramAddressSync([
|
|
613
626
|
Buffer.from("quote"),
|
|
614
627
|
this.maker.marketAddress.toBuffer(),
|
|
615
628
|
this.maker.options.maker.toBuffer(),
|
|
@@ -618,7 +631,7 @@ class MakerBot {
|
|
|
618
631
|
}
|
|
619
632
|
async reconcile() {
|
|
620
633
|
const state = this.state;
|
|
621
|
-
if (state.quote && !await this.maker.options.connection.getAccountInfo(new
|
|
634
|
+
if (state.quote && !await this.maker.options.connection.getAccountInfo(new PublicKey2(state.quote), "confirmed")) {
|
|
622
635
|
if (!state.request || state.request.expiresAt + 180 < Math.floor(Date.now() / 1000)) {
|
|
623
636
|
state.quote = undefined;
|
|
624
637
|
state.request = undefined;
|
|
@@ -627,12 +640,27 @@ class MakerBot {
|
|
|
627
640
|
}
|
|
628
641
|
}
|
|
629
642
|
if (state.replacement) {
|
|
630
|
-
const flow = this.maker.quote.replacement(new
|
|
643
|
+
const flow = this.maker.quote.replacement(new PublicKey2(state.replacement.prior), state.replacement.nonce);
|
|
631
644
|
const [prior, next] = await Promise.all([
|
|
632
|
-
this.maker.options.connection.getAccountInfo(new
|
|
645
|
+
this.maker.options.connection.getAccountInfo(new PublicKey2(state.replacement.prior), "confirmed"),
|
|
633
646
|
this.maker.options.connection.getAccountInfo(flow.nextId, "confirmed")
|
|
634
647
|
]);
|
|
635
|
-
|
|
648
|
+
const successor = next && await this.maker.quoteState(flow.nextId);
|
|
649
|
+
const predecessor = prior && await this.maker.quoteState(new PublicKey2(state.replacement.prior));
|
|
650
|
+
const completed = predecessor && successor && terminal.has(Object.keys(predecessor.status)[0]) && "active" in successor.status && predecessor.replacementNonce?.toString() === state.replacement.nonce.toString();
|
|
651
|
+
if (successor && (!prior || completed)) {
|
|
652
|
+
if (!successor.operator.equals(this.maker.options.wallet.publicKey) || !state.replacement.request || BigInt(successor.capacity.toString()) !== state.replacement.request.maxCapacity)
|
|
653
|
+
throw new Error("Recovered successor does not match this operator's checkpoint");
|
|
654
|
+
const risk = state.replacement.risk;
|
|
655
|
+
if (risk && "active" in successor.status) {
|
|
656
|
+
const account = await this.maker.read("MarketAccount", this.maker.marketAccount());
|
|
657
|
+
const version = BigInt(account.version.toString());
|
|
658
|
+
if ("ready" in account.status && version === risk.version + 1n) {
|
|
659
|
+
risk.version = version;
|
|
660
|
+
risk.balanceNonce = Buffer.from(successor.balanceNonce).toString("hex");
|
|
661
|
+
state.quoteWrite = undefined;
|
|
662
|
+
}
|
|
663
|
+
}
|
|
636
664
|
state.quote = flow.nextId.toBase58();
|
|
637
665
|
state.request = state.replacement.request;
|
|
638
666
|
state.referencePrice = state.replacement.referencePrice;
|
|
@@ -658,14 +686,14 @@ class MakerBot {
|
|
|
658
686
|
const allowed = new Set([
|
|
659
687
|
state.quote,
|
|
660
688
|
state.replacement?.prior,
|
|
661
|
-
state.replacement ? this.maker.quote.replacement(new
|
|
689
|
+
state.replacement ? this.maker.quote.replacement(new PublicKey2(state.replacement.prior), state.replacement.nonce).nextId.toBase58() : undefined,
|
|
662
690
|
this.requestId()?.toBase58()
|
|
663
691
|
].filter(Boolean));
|
|
664
692
|
for (const id of managed)
|
|
665
693
|
if (!allowed.has(id)) {
|
|
666
|
-
const quote = await this.maker.quote.get(new
|
|
694
|
+
const quote = await this.maker.quote.get(new PublicKey2(id)).status();
|
|
667
695
|
if (["active", "waiting", "validated", "validating", "closing"].includes(quote.status))
|
|
668
|
-
await this.maker.quote.get(new
|
|
696
|
+
await this.maker.quote.get(new PublicKey2(id)).cancel();
|
|
669
697
|
}
|
|
670
698
|
}
|
|
671
699
|
async fills() {
|
|
@@ -702,7 +730,7 @@ class MakerBot {
|
|
|
702
730
|
const state = this.state;
|
|
703
731
|
let successorPending = false;
|
|
704
732
|
if (state.replacement?.request) {
|
|
705
|
-
const next = this.maker.quote.replacement(new
|
|
733
|
+
const next = this.maker.quote.replacement(new PublicKey2(state.replacement.prior), state.replacement.nonce).nextId;
|
|
706
734
|
if (await this.maker.options.connection.getAccountInfo(next, "confirmed")) {
|
|
707
735
|
const handle2 = this.maker.quote.get(next);
|
|
708
736
|
const snapshot = await handle2.status();
|
|
@@ -733,7 +761,7 @@ class MakerBot {
|
|
|
733
761
|
return true;
|
|
734
762
|
}
|
|
735
763
|
}
|
|
736
|
-
const handle = this.maker.quote.get(new
|
|
764
|
+
const handle = this.maker.quote.get(new PublicKey2(state.quote));
|
|
737
765
|
const quote = await handle.status();
|
|
738
766
|
if (terminal.has(quote.status)) {
|
|
739
767
|
if (successorPending)
|
|
@@ -760,7 +788,7 @@ class MakerBot {
|
|
|
760
788
|
async replace(market, now) {
|
|
761
789
|
const state = this.state;
|
|
762
790
|
const replacement = state.replacement;
|
|
763
|
-
const flow = this.maker.quote.replacement(new
|
|
791
|
+
const flow = this.maker.quote.replacement(new PublicKey2(replacement.prior), replacement.nonce);
|
|
764
792
|
if (now - market.oracleTimestamp.toNumber() > market.config.maxOracleAgeSeconds - Math.min(Math.floor(market.config.maxOracleAgeSeconds / 2), this.policy.lifetimeSeconds))
|
|
765
793
|
return this.snapshot("pending", "waiting for a fresh oracle update");
|
|
766
794
|
if (!replacement.request) {
|
|
@@ -779,12 +807,12 @@ class MakerBot {
|
|
|
779
807
|
}
|
|
780
808
|
this.inventoryVersion = this.position.version;
|
|
781
809
|
this.dirty = false;
|
|
782
|
-
const previous2 = await this.maker.quote.get(new
|
|
810
|
+
const previous2 = await this.maker.quote.get(new PublicKey2(replacement.prior)).status();
|
|
783
811
|
const policy = this.quotePolicy(market);
|
|
784
812
|
const planned = botQuote(policy, market, this.position, replacement.nonce, now, this.pricing);
|
|
785
813
|
let credit = 0n;
|
|
786
814
|
if (previous2.status === "active" && (!planned || planned.maxCapacity < policy.maxCapacity)) {
|
|
787
|
-
this.reservationView ??= this.maker.quote.get(new
|
|
815
|
+
this.reservationView ??= this.maker.quote.get(new PublicKey2(replacement.prior));
|
|
788
816
|
const margin = await this.reservationView.reservation();
|
|
789
817
|
if (margin === undefined)
|
|
790
818
|
return this.snapshot("pending", "reading remaining quote margin");
|
|
@@ -811,7 +839,7 @@ class MakerBot {
|
|
|
811
839
|
await this.store.save(state);
|
|
812
840
|
return this.snapshot("pending", "retrying expired successor");
|
|
813
841
|
}
|
|
814
|
-
const prior = this.maker.quote.get(new
|
|
842
|
+
const prior = this.maker.quote.get(new PublicKey2(replacement.prior));
|
|
815
843
|
const previous = await prior.status();
|
|
816
844
|
if (previous.status === "active" && ["validated", "reserving"].includes(snapshot.status)) {
|
|
817
845
|
const price = BigInt(market.oraclePriceE8.toString());
|
|
@@ -869,16 +897,16 @@ class MakerBot {
|
|
|
869
897
|
state.quote,
|
|
870
898
|
state.replacement?.prior,
|
|
871
899
|
this.requestId()?.toBase58(),
|
|
872
|
-
state.replacement ? this.maker.quote.replacement(new
|
|
900
|
+
state.replacement ? this.maker.quote.replacement(new PublicKey2(state.replacement.prior), state.replacement.nonce).nextId.toBase58() : undefined
|
|
873
901
|
].filter((id) => Boolean(id))
|
|
874
902
|
});
|
|
875
903
|
this.lastCleanup = Date.now();
|
|
876
904
|
}
|
|
877
|
-
let [market, lamports] = await Promise.all([
|
|
905
|
+
let [market, lamports, now] = await Promise.all([
|
|
878
906
|
this.maker.read("Market", this.maker.marketAddress),
|
|
879
|
-
this.maker.options.connection.getBalance(this.maker.options.wallet.publicKey, "confirmed")
|
|
907
|
+
this.maker.options.connection.getBalance(this.maker.options.wallet.publicKey, "confirmed"),
|
|
908
|
+
chainTime(this.maker.options.connection)
|
|
880
909
|
]);
|
|
881
|
-
let now = Math.floor(Date.now() / 1000);
|
|
882
910
|
const reason = this.stopping ? "shutdown" : quoteHealth(market, now) ?? (BigInt(lamports) < (this.policy.gasReserveLamports ?? 50000000n) ? "operator SOL reserve" : undefined);
|
|
883
911
|
if (reason) {
|
|
884
912
|
const stopped = await this.cancel();
|
|
@@ -896,7 +924,7 @@ class MakerBot {
|
|
|
896
924
|
return this.snapshot("pending", hedgeReason);
|
|
897
925
|
if (this.hedge) {
|
|
898
926
|
market = await this.maker.read("Market", this.maker.marketAddress);
|
|
899
|
-
now =
|
|
927
|
+
now = await chainTime(this.maker.options.connection);
|
|
900
928
|
const changed = quoteHealth(market, now);
|
|
901
929
|
if (changed) {
|
|
902
930
|
const stopped = await this.cancel();
|
|
@@ -910,7 +938,7 @@ class MakerBot {
|
|
|
910
938
|
await this.store.save(state);
|
|
911
939
|
}
|
|
912
940
|
if (state.quote) {
|
|
913
|
-
const handle2 = this.maker.quote.get(new
|
|
941
|
+
const handle2 = this.maker.quote.get(new PublicKey2(state.quote));
|
|
914
942
|
const quote = await handle2.status();
|
|
915
943
|
if (terminal.has(quote.status)) {
|
|
916
944
|
state.quote = undefined;
|
|
@@ -1010,7 +1038,7 @@ class MakerBot {
|
|
|
1010
1038
|
const state = this.state;
|
|
1011
1039
|
if (this.hedge && (state.hedge?.pending || state.inventoryPendingSince !== undefined && Date.now() - state.inventoryPendingSince >= this.hedge.policy.maxUnhedgedMs))
|
|
1012
1040
|
return;
|
|
1013
|
-
const handle = this.maker.quote.get(new
|
|
1041
|
+
const handle = this.maker.quote.get(new PublicKey2(state.quote));
|
|
1014
1042
|
const quote = await this.maker.quoteState(handle.id);
|
|
1015
1043
|
if (!("active" in quote.status) || quote.expiry.toNumber() <= now)
|
|
1016
1044
|
return;
|
|
@@ -1022,7 +1050,24 @@ class MakerBot {
|
|
|
1022
1050
|
const drift = price > reference ? price - reference : reference - price;
|
|
1023
1051
|
if (!quote.marketRevision.eq(market.revision) || reference <= 0n || drift * 10000n > reference * BigInt(Math.min(Math.floor(market.config.maxQuoteDeviationBps / 4), 25)))
|
|
1024
1052
|
return;
|
|
1025
|
-
|
|
1053
|
+
let renewed;
|
|
1054
|
+
try {
|
|
1055
|
+
renewed = await handle.renew({ validForSeconds: duration });
|
|
1056
|
+
} catch (error) {
|
|
1057
|
+
const code = error.error?.errorCode?.code;
|
|
1058
|
+
if (!["InvalidQuote", "WrongQuoteStatus"].includes(code ?? ""))
|
|
1059
|
+
throw error;
|
|
1060
|
+
const [latest, current] = await Promise.all([
|
|
1061
|
+
this.maker.read("Market", this.maker.marketAddress),
|
|
1062
|
+
this.maker.quoteState(handle.id)
|
|
1063
|
+
]);
|
|
1064
|
+
const currentPrice = BigInt(latest.oraclePriceE8.toString());
|
|
1065
|
+
const quotedPrice = BigInt(current.oracleReferenceE8.toString());
|
|
1066
|
+
const moved = currentPrice > quotedPrice ? currentPrice - quotedPrice : quotedPrice - currentPrice;
|
|
1067
|
+
if (!("active" in current.status) || current.expiry.toNumber() <= Math.floor(Date.now() / 1000) || !current.marketRevision.eq(latest.revision) || quoteHealth(latest, Math.floor(Date.now() / 1000)) || moved * 10000n > quotedPrice * BigInt(Math.min(Math.floor(latest.config.maxQuoteDeviationBps / 4), 25)))
|
|
1068
|
+
return;
|
|
1069
|
+
throw error;
|
|
1070
|
+
}
|
|
1026
1071
|
if (state.request)
|
|
1027
1072
|
state.request.expiresAt = renewed.expiresAt;
|
|
1028
1073
|
await this.store.save(state);
|