@depthhq/maker-sdk 0.1.0 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  // src/client/client.ts
2
- import { Buffer as Buffer6 } from "buffer";
2
+ import { Buffer as Buffer8 } from "buffer";
3
3
  import * as anchor6 from "@anchor-lang/core";
4
4
 
5
5
  // ../../node_modules/@arcium-hq/client/build/index.mjs
@@ -24910,13 +24910,521 @@ import {
24910
24910
  } from "@depthhq/bindings";
24911
24911
  import { DepthView } from "@depthhq/sdk/views";
24912
24912
  import { DepthRecovery } from "@depthhq/sdk/recovery";
24913
- import { PublicKey as PublicKey5 } from "@solana/web3.js";
24913
+ import { PublicKey as PublicKey7 } from "@solana/web3.js";
24914
24914
 
24915
24915
  // src/chain/random.ts
24916
24916
  function randomBytes3(length) {
24917
24917
  return crypto.getRandomValues(new Uint8Array(length));
24918
24918
  }
24919
24919
 
24920
+ // src/hedge/access.ts
24921
+ import { Buffer as Buffer2 } from "buffer";
24922
+
24923
+ // src/hedge/schema.ts
24924
+ var object = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
24925
+ var integer = (value) => Number.isSafeInteger(value) && value >= 0;
24926
+ var amount = (value) => typeof value === "string" && /^-?\d{1,40}$/.test(value);
24927
+ var optional = (value, check) => value === undefined || check(value);
24928
+ var text = (value) => typeof value === "string" && value.length <= 1024;
24929
+ function order(value, receipt = false) {
24930
+ if (!object(value) || typeof value.cloid !== "string" || !/^0x[0-9a-f]{32}$/.test(value.cloid) || !integer(value.nonce) || !integer(value.expiresAt) || value.expiresAt <= value.nonce || typeof value.buy !== "boolean" || typeof value.reduceOnly !== "boolean" || !amount(value.size) || BigInt(value.size) <= 0n || !amount(value.limitPriceE8) || BigInt(value.limitPriceE8) <= 0n)
24931
+ return false;
24932
+ if (!receipt)
24933
+ return true;
24934
+ 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) && 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)));
24935
+ }
24936
+ function hedgeView(value, owner) {
24937
+ if (!object(value) || value.maker !== owner || typeof value.enabled !== "boolean")
24938
+ throw new Error("Maker hedge response belongs to another wallet or is invalid");
24939
+ const snapshot = value.snapshot;
24940
+ 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))))
24941
+ throw new Error("Maker hedge response is invalid");
24942
+ return value;
24943
+ }
24944
+
24945
+ // src/hedge/access.ts
24946
+ var accessMessage = (wallet, nonce, expiresAt, scope = "Read hedge history") => `Depth maker access
24947
+ Wallet: ${wallet}
24948
+ Scope: ${scope}
24949
+ Nonce: ${nonce}
24950
+ Expires: ${expiresAt}`;
24951
+
24952
+ class WalletSession {
24953
+ options;
24954
+ scope;
24955
+ prefix;
24956
+ token;
24957
+ constructor(options, scope = "Read hedge history", prefix = "") {
24958
+ this.options = options;
24959
+ this.scope = scope;
24960
+ this.prefix = prefix;
24961
+ }
24962
+ async request(path, init) {
24963
+ if (!this.options.serviceUrl)
24964
+ throw new Error("A maker service URL is required");
24965
+ const response = await fetch(`${this.options.serviceUrl.replace(/\/$/, "")}/v1/maker/${`${this.prefix}${path}`.replace(/\/$/, "")}`, {
24966
+ ...init,
24967
+ cache: "no-store",
24968
+ signal: AbortSignal.timeout(15000)
24969
+ });
24970
+ if (response.status === 401) {
24971
+ this.token = undefined;
24972
+ throw new Error("Authorize access with your maker wallet");
24973
+ }
24974
+ if (!response.ok) {
24975
+ const error = await response.json().catch(() => ({}));
24976
+ throw new Error(typeof error.message === "string" ? error.message : response.status === 403 ? "This worker belongs to another maker" : "Maker worker is unavailable");
24977
+ }
24978
+ return response.json();
24979
+ }
24980
+ async authorize() {
24981
+ const wallet = this.options.wallet;
24982
+ if (!wallet.signMessage)
24983
+ throw new Error("This wallet cannot sign access messages");
24984
+ const challenge = await this.request(`challenge?wallet=${wallet.publicKey.toBase58()}`);
24985
+ if (challenge.wallet !== wallet.publicKey.toBase58() || !/^[0-9a-f]{64}$/.test(challenge.nonce) || !Number.isSafeInteger(challenge.expiresAt) || challenge.expiresAt <= Date.now() || challenge.expiresAt > Date.now() + 120000 || challenge.message !== accessMessage(challenge.wallet, challenge.nonce, challenge.expiresAt, this.scope))
24986
+ throw new Error("Maker access challenge is invalid");
24987
+ const signature = await wallet.signMessage(new TextEncoder().encode(challenge.message));
24988
+ const session = await this.request("session", {
24989
+ method: "POST",
24990
+ headers: { "content-type": "application/json" },
24991
+ body: JSON.stringify({
24992
+ nonce: challenge.nonce,
24993
+ signature: Buffer2.from(signature).toString("base64")
24994
+ })
24995
+ });
24996
+ if (!/^[0-9a-f]{64}$/.test(session.token) || !Number.isSafeInteger(session.expiresAt) || session.expiresAt <= Date.now() || session.expiresAt > Date.now() + 16 * 60000)
24997
+ throw new Error("Maker access session is invalid");
24998
+ this.token = { value: session.token, expiresAt: session.expiresAt };
24999
+ }
25000
+ async authorizedRequest(path, body) {
25001
+ if (!this.token || this.token.expiresAt <= Date.now())
25002
+ await this.authorize();
25003
+ return this.request(path, {
25004
+ method: body === undefined ? "GET" : "POST",
25005
+ headers: {
25006
+ authorization: `Bearer ${this.token.value}`,
25007
+ "content-type": "application/json"
25008
+ },
25009
+ body: body === undefined ? undefined : JSON.stringify(body)
25010
+ });
25011
+ }
25012
+ disconnect() {
25013
+ this.token = undefined;
25014
+ }
25015
+ }
25016
+
25017
+ class MakerAccess extends WalletSession {
25018
+ async summary() {
25019
+ if (!this.token || this.token.expiresAt <= Date.now()) {
25020
+ this.token = undefined;
25021
+ throw new Error("Authorize access with your maker wallet");
25022
+ }
25023
+ return hedgeView(await this.authorizedRequest("hedges"), this.options.wallet.publicKey.toBase58());
25024
+ }
25025
+ }
25026
+
25027
+ // src/automation/automation.ts
25028
+ import { PublicKey as PublicKey3, SystemProgram, Transaction } from "@solana/web3.js";
25029
+ import { Buffer as Buffer3 } from "buffer";
25030
+
25031
+ // src/hedge/setup.ts
25032
+ import { ExchangeClient, HttpTransport, InfoClient } from "@nktkas/hyperliquid";
25033
+ import {
25034
+ getWalletAddress
25035
+ } from "@nktkas/hyperliquid/signing";
25036
+ import { privateKeyToAccount } from "viem/accounts";
25037
+
25038
+ // src/hedge/amount.ts
25039
+ function units(value, decimals, exact = true) {
25040
+ if (!/^-?\d+(?:\.\d+)?$/.test(value))
25041
+ throw new Error("External decimal is invalid");
25042
+ const negative = value.startsWith("-");
25043
+ const [whole, fraction = ""] = value.replace(/^-/, "").split(".");
25044
+ const extra = fraction.slice(decimals);
25045
+ if (exact && /[1-9]/.test(extra))
25046
+ throw new Error("External decimal exceeds precision");
25047
+ const amount2 = BigInt(whole) * 10n ** BigInt(decimals) + BigInt(fraction.slice(0, decimals).padEnd(decimals, "0") || "0");
25048
+ return negative ? -amount2 - (!exact && /[1-9]/.test(extra) ? 1n : 0n) : amount2;
25049
+ }
25050
+
25051
+ // src/hedge/setup.ts
25052
+ async function verify_hyperliquid(options) {
25053
+ const info = new InfoClient({
25054
+ transport: new HttpTransport({ isTestnet: options.network === "testnet" })
25055
+ });
25056
+ const [state, agents] = await Promise.all([
25057
+ info.clearinghouseState({ user: options.account }),
25058
+ info.extraAgents({ user: options.account })
25059
+ ]);
25060
+ if (units(state.withdrawable, 6, false) < 10000000n)
25061
+ throw new Error(`Fund Hyperliquid ${options.network} account ${options.account} with at least 10 available USDC`);
25062
+ if (!agents.some((entry) => entry.address.toLowerCase() === options.agent.toLowerCase() && (entry.validUntil === null || entry.validUntil > Date.now())))
25063
+ throw new Error("Approve the displayed agent in Hyperliquid API wallets, or connect its account wallet");
25064
+ const position = state.assetPositions.find((entry) => entry.position.coin === "SOL")?.position;
25065
+ if (position && position.leverage.value > options.maxLeverage)
25066
+ throw new Error("SOL leverage exceeds the configured hedge limit");
25067
+ }
25068
+ async function setup_hyperliquid(options) {
25069
+ if (Boolean(options.wallet) === Boolean(options.accountKey))
25070
+ throw new Error("Provide one Hyperliquid account signer source");
25071
+ if (!Number.isInteger(options.leverage) || options.leverage < 1 || options.leverage > 10)
25072
+ throw new Error("Setup leverage must be 1 to 10");
25073
+ if (Boolean(options.agent) === Boolean(options.agentKey))
25074
+ throw new Error("Provide one Hyperliquid agent identity source");
25075
+ const agent = options.agent ?? privateKeyToAccount(options.agentKey).address;
25076
+ if (!/^0x[0-9a-fA-F]{40}$/.test(agent))
25077
+ throw new Error("Hyperliquid agent address is invalid");
25078
+ const wallet = options.wallet ?? privateKeyToAccount(options.accountKey);
25079
+ const account = await getWalletAddress(wallet);
25080
+ if (options.account && account.toLowerCase() !== options.account.toLowerCase())
25081
+ throw new Error("The setup signer does not own the configured Hyperliquid account");
25082
+ if (account.toLowerCase() === agent.toLowerCase())
25083
+ throw new Error("The account and agent must be separate wallets");
25084
+ const transport = new HttpTransport({
25085
+ isTestnet: (options.network ?? "testnet") === "testnet"
25086
+ });
25087
+ const info = new InfoClient({ transport });
25088
+ const state = await info.clearinghouseState({ user: account });
25089
+ if (units(state.marginSummary.accountValue, 6, false) < 10000000n)
25090
+ throw new Error(`Fund Hyperliquid ${options.network ?? "testnet"} account ${account} with at least 10 USDC before setup`);
25091
+ const client = new ExchangeClient({ wallet, transport });
25092
+ const agents = await info.extraAgents({ user: account });
25093
+ if (!agents.some((entry) => entry.address.toLowerCase() === agent.toLowerCase() && (entry.validUntil === null || entry.validUntil > Date.now())))
25094
+ await client.approveAgent({
25095
+ agentAddress: agent,
25096
+ agentName: options.agentName ?? "Depth maker"
25097
+ });
25098
+ const meta = await info.meta();
25099
+ const asset = meta.universe.findIndex((entry) => entry.name === "SOL" && !entry.isDelisted);
25100
+ if (asset < 0)
25101
+ throw new Error("Hyperliquid SOL perpetual is unavailable");
25102
+ await client.updateLeverage({
25103
+ asset,
25104
+ isCross: true,
25105
+ leverage: options.leverage
25106
+ });
25107
+ return {
25108
+ account,
25109
+ agent,
25110
+ network: options.network ?? "testnet",
25111
+ leverage: options.leverage
25112
+ };
25113
+ }
25114
+
25115
+ // src/automation/types.ts
25116
+ import { PublicKey as PublicKey2 } from "@solana/web3.js";
25117
+
25118
+ // src/bot/policy.ts
25119
+ import { positionPnl } from "@depthhq/sdk";
25120
+
25121
+ // src/hedge/policy.ts
25122
+ function validateHedgePolicy(policy) {
25123
+ if (!Number.isInteger(policy.maxLeverage) || policy.maxLeverage < 1 || policy.maxLeverage > 10)
25124
+ throw new RangeError("Maximum hedge leverage must be 1 to 10");
25125
+ if (!Number.isInteger(policy.ratioBps) || policy.ratioBps < 1 || policy.ratioBps > 1e4)
25126
+ throw new RangeError("Hedge ratio must be 1 to 10000 bps");
25127
+ if (policy.thresholdNotional <= 0n || policy.maxOrderNotional <= 0n || policy.maxUnhedgedNotional <= policy.thresholdNotional)
25128
+ throw new RangeError("Hedge notional limits are invalid");
25129
+ for (const value of [
25130
+ policy.batchMs,
25131
+ policy.maxUnhedgedMs,
25132
+ policy.maxPriceAgeMs,
25133
+ policy.orderTtlMs
25134
+ ])
25135
+ if (!Number.isSafeInteger(value) || value < 1 || value > 300000)
25136
+ throw new RangeError("Hedge time limits must be 1 to 300000 ms");
25137
+ if (policy.batchMs >= policy.maxUnhedgedMs || policy.orderTtlMs > policy.maxUnhedgedMs)
25138
+ throw new RangeError("Hedge batching and order expiry must fit the exposure time limit");
25139
+ if (!Number.isInteger(policy.maxSlippageBps) || policy.maxSlippageBps < 1 || policy.maxSlippageBps > 100)
25140
+ throw new RangeError("Hedge slippage must be 1 to 100 bps");
25141
+ }
25142
+
25143
+ // src/bot/policy.ts
25144
+ function validateBotPolicy(policy) {
25145
+ if (policy.maxCapacity <= 0n || policy.maxInventoryNotional <= 0n || policy.maxCapacity > policy.maxInventoryNotional)
25146
+ throw new RangeError("Maker capacity must fit a positive inventory limit");
25147
+ for (const [name, value] of Object.entries(policy))
25148
+ if (typeof value === "number" && (!Number.isSafeInteger(value) || value <= 0) && !(["inventorySkewBps", "executionCostBps"].includes(name) && value === 0))
25149
+ throw new RangeError(`${name} must be a positive integer`);
25150
+ if (policy.refreshSeconds >= policy.lifetimeSeconds)
25151
+ throw new RangeError("Refresh must precede quote expiry");
25152
+ if (policy.spreadBps >= 20000 || policy.repriceBps > 1e4)
25153
+ throw new RangeError("Maker price bounds are invalid");
25154
+ if ((policy.inventorySkewBps ?? 0) > 100 || (policy.executionCostBps ?? 0) > 100)
25155
+ throw new RangeError("Maker pricing adjustments must be 0 to 100 bps");
25156
+ if ((policy.fundingHours ?? 1) > 168)
25157
+ throw new RangeError("Maker funding horizon must be at most 168 hours");
25158
+ const reserve = policy.gasReserveLamports ?? 50000000n;
25159
+ if (reserve < 10000000n || reserve > BigInt(Number.MAX_SAFE_INTEGER))
25160
+ throw new RangeError("Maker SOL reserve must be at least 10000000 lamports");
25161
+ }
25162
+
25163
+ // src/automation/types.ts
25164
+ var amount2 = (value, name) => {
25165
+ if (typeof value !== "string" || !/^\d{1,20}$/.test(value) || BigInt(value) > (1n << 64n) - 1n)
25166
+ throw new Error(`${name} must be an unsigned integer amount`);
25167
+ return BigInt(value);
25168
+ };
25169
+ var object2 = (value, names) => {
25170
+ if (!value || typeof value !== "object" || Array.isArray(value) || Object.keys(value).some((key) => !names.includes(key)))
25171
+ throw new Error("Automation configuration is invalid");
25172
+ return value;
25173
+ };
25174
+ var integer2 = (value, fallback) => {
25175
+ const result = value ?? fallback;
25176
+ if (typeof result !== "number" || !Number.isSafeInteger(result))
25177
+ throw new Error("Automation limits must be integers");
25178
+ return result;
25179
+ };
25180
+ function automationConfig(value) {
25181
+ const input = object2(value, ["quote", "hedge"]);
25182
+ const quote = object2(input.quote, [
25183
+ "maxCapacity",
25184
+ "maxInventoryNotional",
25185
+ "spreadBps",
25186
+ "repriceBps",
25187
+ "lifetimeSeconds",
25188
+ "refreshSeconds",
25189
+ "gasReserveLamports",
25190
+ "inventorySkewBps",
25191
+ "executionCostBps",
25192
+ "fundingHours"
25193
+ ]);
25194
+ const policy = {
25195
+ maxCapacity: amount2(quote.maxCapacity, "Capacity"),
25196
+ maxInventoryNotional: amount2(quote.maxInventoryNotional, "Inventory limit"),
25197
+ spreadBps: integer2(quote.spreadBps),
25198
+ repriceBps: integer2(quote.repriceBps),
25199
+ lifetimeSeconds: integer2(quote.lifetimeSeconds),
25200
+ refreshSeconds: integer2(quote.refreshSeconds),
25201
+ gasReserveLamports: amount2(quote.gasReserveLamports ?? "50000000", "SOL reserve"),
25202
+ inventorySkewBps: integer2(quote.inventorySkewBps, 15),
25203
+ executionCostBps: integer2(quote.executionCostBps, 5),
25204
+ fundingHours: integer2(quote.fundingHours, 1)
25205
+ };
25206
+ validateBotPolicy(policy);
25207
+ if (policy.lifetimeSeconds > 86400 || policy.refreshSeconds > 86400)
25208
+ throw new Error("Quote lifetime must be at most one day");
25209
+ if (input.hedge === undefined)
25210
+ return { quote: policy };
25211
+ const hedge = object2(input.hedge, ["account", "policy"]);
25212
+ if (typeof hedge.account !== "string" || !/^0x[0-9a-fA-F]{40}$/.test(hedge.account))
25213
+ throw new Error("Hyperliquid account address is invalid");
25214
+ const risk = object2(hedge.policy, [
25215
+ "ratioBps",
25216
+ "thresholdNotional",
25217
+ "maxUnhedgedNotional",
25218
+ "maxOrderNotional",
25219
+ "batchMs",
25220
+ "maxUnhedgedMs",
25221
+ "maxSlippageBps",
25222
+ "maxPriceAgeMs",
25223
+ "orderTtlMs",
25224
+ "maxLeverage"
25225
+ ]);
25226
+ const hedgePolicy = {
25227
+ ratioBps: integer2(risk.ratioBps),
25228
+ thresholdNotional: amount2(risk.thresholdNotional, "Hedge threshold"),
25229
+ maxUnhedgedNotional: amount2(risk.maxUnhedgedNotional, "Exposure limit"),
25230
+ maxOrderNotional: amount2(risk.maxOrderNotional, "Order limit"),
25231
+ batchMs: integer2(risk.batchMs),
25232
+ maxUnhedgedMs: integer2(risk.maxUnhedgedMs),
25233
+ maxSlippageBps: integer2(risk.maxSlippageBps),
25234
+ maxPriceAgeMs: integer2(risk.maxPriceAgeMs),
25235
+ orderTtlMs: integer2(risk.orderTtlMs),
25236
+ maxLeverage: integer2(risk.maxLeverage)
25237
+ };
25238
+ validateHedgePolicy(hedgePolicy);
25239
+ return {
25240
+ quote: policy,
25241
+ hedge: {
25242
+ account: hedge.account.toLowerCase(),
25243
+ policy: hedgePolicy
25244
+ }
25245
+ };
25246
+ }
25247
+ var automationWire = (config) => JSON.parse(JSON.stringify(config, (_key, value) => typeof value === "bigint" ? value.toString() : value));
25248
+ function automationView(value, owner, environment) {
25249
+ if (value === null)
25250
+ return null;
25251
+ const view = object2(value, [
25252
+ "owner",
25253
+ "environment",
25254
+ "revision",
25255
+ "operator",
25256
+ "agent",
25257
+ "config",
25258
+ "desired",
25259
+ "phase",
25260
+ "updatedAt",
25261
+ "reason",
25262
+ "bot",
25263
+ "hedge",
25264
+ "funding"
25265
+ ]);
25266
+ if (view.owner !== owner || view.environment !== environment)
25267
+ throw new Error("Automation belongs to another wallet or network");
25268
+ if (typeof view.operator !== "string" || new PublicKey2(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)) || ![
25269
+ "configured",
25270
+ "starting",
25271
+ "running",
25272
+ "pausing",
25273
+ "paused",
25274
+ "blocked"
25275
+ ].includes(String(view.phase)) || view.reason !== undefined && typeof view.reason !== "string")
25276
+ throw new Error("Automation response is invalid");
25277
+ automationConfig(view.config);
25278
+ if (view.bot !== undefined) {
25279
+ const bot = object2(view.bot, ["phase", "reason", "quoteId", "fillCount"]);
25280
+ 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 PublicKey2(bot.quoteId).toBase58() !== bot.quoteId))
25281
+ throw new Error("Automation status is invalid");
25282
+ }
25283
+ hedgeView(view.hedge, owner);
25284
+ if (view.funding !== undefined) {
25285
+ const funding = object2(view.funding, ["signature", "lamports", "status"]);
25286
+ 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)))
25287
+ throw new Error("Operator funding receipt is invalid");
25288
+ amount2(funding.lamports, "Operator funding");
25289
+ }
25290
+ return view;
25291
+ }
25292
+
25293
+ // src/automation/automation.ts
25294
+ class MakerAutomation extends WalletSession {
25295
+ maker;
25296
+ constructor(maker) {
25297
+ super(maker.options, "Manage maker automation", "automation/");
25298
+ this.maker = maker;
25299
+ }
25300
+ view(value) {
25301
+ return automationView(value, this.maker.options.wallet.publicKey.toBase58(), this.maker.options.environment ?? "");
25302
+ }
25303
+ async summary() {
25304
+ if (!this.token || this.token.expiresAt <= Date.now())
25305
+ throw new Error("Authorize automation with your maker wallet");
25306
+ return this.view(await this.authorizedRequest(""));
25307
+ }
25308
+ async configure(config, revision) {
25309
+ const wire = automationWire(config);
25310
+ automationConfig(wire);
25311
+ if (revision === undefined) {
25312
+ if (!this.token || this.token.expiresAt <= Date.now())
25313
+ await this.authorize();
25314
+ revision = (await this.summary())?.revision ?? 0;
25315
+ }
25316
+ if (!Number.isSafeInteger(revision) || revision < 0)
25317
+ throw new Error("Automation revision is invalid");
25318
+ return this.view(await this.authorizedRequest("configure", { revision, config: wire }));
25319
+ }
25320
+ async approve(profile, options = {}) {
25321
+ this.view(profile);
25322
+ const current = await this.summary();
25323
+ if (!current || current.revision !== profile.revision || current.operator !== profile.operator || current.agent !== profile.agent)
25324
+ throw new Error("Automation configuration changed; review it again");
25325
+ if (!this.maker.options.maker.equals(this.maker.options.wallet.publicKey))
25326
+ throw new Error("The maker owner must approve automation");
25327
+ if (current.desired !== "paused" || !["configured", "paused"].includes(current.phase))
25328
+ throw new Error("Pause automation before approving its operator");
25329
+ const config = automationConfig(current.config);
25330
+ const grantSeconds = options.grantSeconds ?? 86400;
25331
+ if (!Number.isSafeInteger(grantSeconds) || grantSeconds < 60 || grantSeconds > 604800)
25332
+ throw new Error("Operator approval must last 1 minute to 7 days");
25333
+ const target = options.operatorFundingLamports ?? config.quote.gasReserveLamports + 200000000n;
25334
+ if (target < config.quote.gasReserveLamports || target > 10000000000n)
25335
+ throw new Error("Operator funding must cover the reserve and stay within 10 SOL");
25336
+ if (config.hedge) {
25337
+ const network = profile.environment === "devnet" ? "testnet" : "mainnet";
25338
+ if (options.hedgeWallet)
25339
+ await setup_hyperliquid({
25340
+ wallet: options.hedgeWallet,
25341
+ account: config.hedge.account,
25342
+ agent: profile.agent,
25343
+ network,
25344
+ leverage: config.hedge.policy.maxLeverage,
25345
+ agentName: `Depth ${profile.agent.slice(2, 10)}`
25346
+ });
25347
+ else
25348
+ await verify_hyperliquid({
25349
+ account: config.hedge.account,
25350
+ agent: profile.agent,
25351
+ network,
25352
+ maxLeverage: config.hedge.policy.maxLeverage
25353
+ });
25354
+ }
25355
+ const operator = new PublicKey3(profile.operator);
25356
+ const balance = BigInt(await this.maker.options.connection.getBalance(operator, "confirmed"));
25357
+ const signatures = [];
25358
+ const recovered = this.view(await this.authorizedRequest("fund", { revision: current.revision }));
25359
+ if (recovered.funding?.status === "pending")
25360
+ signatures.push((await this.waitFunding(current.revision)).signature);
25361
+ else if (balance < target) {
25362
+ const blockhash = await this.maker.options.connection.getLatestBlockhash("confirmed");
25363
+ const transaction = new Transaction({
25364
+ ...blockhash,
25365
+ feePayer: this.maker.options.wallet.publicKey
25366
+ }).add(SystemProgram.transfer({
25367
+ fromPubkey: this.maker.options.wallet.publicKey,
25368
+ toPubkey: operator,
25369
+ lamports: target - balance
25370
+ }));
25371
+ const signed = await this.maker.options.wallet.signTransaction(transaction);
25372
+ this.view(await this.authorizedRequest("fund", {
25373
+ revision: current.revision,
25374
+ transaction: Buffer3.from(signed.serialize()).toString("base64"),
25375
+ lastValidBlockHeight: blockhash.lastValidBlockHeight,
25376
+ targetLamports: target.toString()
25377
+ }));
25378
+ signatures.push((await this.waitFunding(current.revision)).signature);
25379
+ }
25380
+ signatures.push(await this.maker.operator.authorize({
25381
+ operator,
25382
+ maxCapacity: config.quote.maxCapacity,
25383
+ expiresAt: Math.floor(Date.now() / 1000) + grantSeconds,
25384
+ canView: true
25385
+ }));
25386
+ return { profile: current, signatures };
25387
+ }
25388
+ async waitFunding(revision) {
25389
+ const deadline = Date.now() + 120000;
25390
+ for (;; ) {
25391
+ const profile = this.view(await this.authorizedRequest("fund", { revision }));
25392
+ const receipt = profile.funding;
25393
+ if (!receipt)
25394
+ throw new Error("Operator funding receipt is unavailable");
25395
+ if (receipt.status === "confirmed")
25396
+ return receipt;
25397
+ if (receipt.status !== "pending")
25398
+ throw new Error(`Operator funding ${receipt.status}; retry approval after reviewing its receipt`);
25399
+ if (Date.now() >= deadline)
25400
+ throw new Error("Operator funding is pending; its signed transaction is saved and approval can resume");
25401
+ await new Promise((resolve) => setTimeout(resolve, 1000));
25402
+ }
25403
+ }
25404
+ async command(action, revision) {
25405
+ if (revision === undefined) {
25406
+ if (!this.token || this.token.expiresAt <= Date.now())
25407
+ await this.authorize();
25408
+ const profile = await this.summary();
25409
+ if (!profile)
25410
+ throw new Error("Configure maker automation first");
25411
+ revision = profile.revision;
25412
+ }
25413
+ if (!Number.isSafeInteger(revision) || revision < 1)
25414
+ throw new Error("Automation revision is invalid");
25415
+ return this.view(await this.authorizedRequest(action, { revision }));
25416
+ }
25417
+ start(revision) {
25418
+ return this.command("start", revision);
25419
+ }
25420
+ pause(revision) {
25421
+ return this.command("pause", revision);
25422
+ }
25423
+ resume(revision) {
25424
+ return this.start(revision);
25425
+ }
25426
+ }
25427
+
24920
25428
  // src/client/client.ts
24921
25429
  import {
24922
25430
  DepthClient,
@@ -24927,7 +25435,7 @@ import {
24927
25435
  } from "@depthhq/sdk";
24928
25436
 
24929
25437
  // src/chain/arcium.ts
24930
- import { Buffer as Buffer2 } from "buffer";
25438
+ import { Buffer as Buffer4 } from "buffer";
24931
25439
  import { computationName, DEPTH_PROGRAM_ID } from "@depthhq/bindings";
24932
25440
  function mxeAccount(provider) {
24933
25441
  const arcium2 = getArciumProgram(provider);
@@ -24939,7 +25447,7 @@ async function queueAccounts(provider, connection, name, offset) {
24939
25447
  if (!mxe.mxeProgramId.equals(DEPTH_PROGRAM_ID)) {
24940
25448
  throw new Error("MXE is registered for another program");
24941
25449
  }
24942
- const definition = getCompDefAccAddress(DEPTH_PROGRAM_ID, Buffer2.from(getCompDefAccOffset(computationName(name))).readUInt32LE());
25450
+ const definition = getCompDefAccAddress(DEPTH_PROGRAM_ID, Buffer4.from(getCompDefAccOffset(computationName(name))).readUInt32LE());
24943
25451
  if (!await connection.getAccountInfo(definition, "confirmed")) {
24944
25452
  throw new Error(`${name} computation is not deployed`);
24945
25453
  }
@@ -24954,11 +25462,11 @@ async function queueAccounts(provider, connection, name, offset) {
24954
25462
  }
24955
25463
 
24956
25464
  // src/backstop/backstop.ts
24957
- import { Buffer as Buffer3 } from "buffer";
25465
+ import { Buffer as Buffer5 } from "buffer";
24958
25466
  import * as anchor2 from "@anchor-lang/core";
24959
25467
  import { DEPTH_PROGRAM_ID as DEPTH_PROGRAM_ID2, SOL_USD_MARKET_ID } from "@depthhq/bindings";
24960
25468
  import { DepthError } from "@depthhq/sdk";
24961
- import { PublicKey as PublicKey2 } from "@solana/web3.js";
25469
+ import { PublicKey as PublicKey4 } from "@solana/web3.js";
24962
25470
  function u64(value, name) {
24963
25471
  if (typeof value !== "bigint" || value < 0n || value > (1n << 64n) - 1n)
24964
25472
  throw new RangeError(`${name} must be an unsigned 64-bit bigint`);
@@ -24974,8 +25482,8 @@ function timing(options) {
24974
25482
  return { timeoutMs, pollMs };
24975
25483
  }
24976
25484
  function address2(market, maker, nonce) {
24977
- const bytes = u64(nonce, "clientNonce").toArrayLike(Buffer3, "le", 8);
24978
- return PublicKey2.findProgramAddressSync([Buffer3.from("backstop"), market.toBuffer(), maker.toBuffer(), bytes], DEPTH_PROGRAM_ID2)[0];
25485
+ const bytes = u64(nonce, "clientNonce").toArrayLike(Buffer5, "le", 8);
25486
+ return PublicKey4.findProgramAddressSync([Buffer5.from("backstop"), market.toBuffer(), maker.toBuffer(), bytes], DEPTH_PROGRAM_ID2)[0];
24979
25487
  }
24980
25488
  async function poll(read, terminal, options) {
24981
25489
  const { timeoutMs, pollMs } = timing(options);
@@ -25017,7 +25525,7 @@ class BackstopHandle {
25017
25525
  ]);
25018
25526
  const now = Math.floor(Date.now() / 1000);
25019
25527
  const margin = (input.maxCapacity * BigInt(market.config.initialMarginBps) + 9999n) / 10000n;
25020
- if (!market.backstopOffer.equals(PublicKey2.default) || market.pendingOrders !== 0 || Object.keys(market.status)[0] === "settling" || input.maxCapacity > BigInt(market.config.maxAccountNotional.toString()) || margin < BigInt(market.config.backstopMinCollateral.toString()))
25528
+ if (!market.backstopOffer.equals(PublicKey4.default) || market.pendingOrders !== 0 || Object.keys(market.status)[0] === "settling" || input.maxCapacity > BigInt(market.config.maxAccountNotional.toString()) || margin < BigInt(market.config.backstopMinCollateral.toString()))
25021
25529
  throw new Error("Backstop offer is outside the current market policy");
25022
25530
  if (!account.owner.equals(client.options.maker) || !account.market.equals(client.marketAddress) || !("ready" in account.status))
25023
25531
  throw new Error("Maker market account is unavailable");
@@ -25103,9 +25611,9 @@ class BackstopRelease {
25103
25611
  }
25104
25612
 
25105
25613
  // src/fill/history.ts
25106
- import { Buffer as Buffer4 } from "buffer";
25614
+ import { Buffer as Buffer6 } from "buffer";
25107
25615
  import * as anchor3 from "@anchor-lang/core";
25108
- import { PublicKey as PublicKey3 } from "@solana/web3.js";
25616
+ import { PublicKey as PublicKey5 } from "@solana/web3.js";
25109
25617
 
25110
25618
  class FillHistory {
25111
25619
  client;
@@ -25144,20 +25652,20 @@ class FillHistory {
25144
25652
  ...transaction.transaction.message.compiledInstructions.map((ix) => ({
25145
25653
  programIdIndex: ix.programIdIndex,
25146
25654
  accounts: ix.accountKeyIndexes,
25147
- data: Buffer4.from(ix.data)
25655
+ data: Buffer6.from(ix.data)
25148
25656
  })),
25149
25657
  ...(transaction.meta?.innerInstructions ?? []).flatMap((group) => group.instructions.map((ix) => ({
25150
25658
  programIdIndex: ix.programIdIndex,
25151
25659
  accounts: ix.accounts,
25152
- data: Buffer4.from(anchor3.utils.bytes.bs58.decode(ix.data))
25660
+ data: Buffer6.from(anchor3.utils.bytes.bs58.decode(ix.data))
25153
25661
  })))
25154
25662
  ];
25155
25663
  for (const ix of instructions2) {
25156
- if (!keys.get(ix.programIdIndex)?.equals(this.client.program.programId) || !ix.data.subarray(0, 8).equals(Buffer4.from(definition.discriminator)))
25664
+ if (!keys.get(ix.programIdIndex)?.equals(this.client.program.programId) || !ix.data.subarray(0, 8).equals(Buffer6.from(definition.discriminator)))
25157
25665
  continue;
25158
- const order = keys.get(ix.accounts[orderIndex]);
25159
- if (order)
25160
- orders.set(order.toBase58(), {
25666
+ const order2 = keys.get(ix.accounts[orderIndex]);
25667
+ if (order2)
25668
+ orders.set(order2.toBase58(), {
25161
25669
  signature: signature.signature,
25162
25670
  slot: signature.slot
25163
25671
  });
@@ -25168,12 +25676,12 @@ class FillHistory {
25168
25676
  const fills = [];
25169
25677
  for (let i = 0;i < addresses.length; i += 100) {
25170
25678
  const batch = addresses.slice(i, i + 100);
25171
- const accounts2 = await connection.getMultipleAccountsInfo(batch.map((id) => new PublicKey3(id)), "finalized");
25679
+ const accounts2 = await connection.getMultipleAccountsInfo(batch.map((id) => new PublicKey5(id)), "finalized");
25172
25680
  accounts2.forEach((info, index) => {
25173
25681
  if (!info || !info.owner.equals(this.client.program.programId))
25174
25682
  throw new Error("Finalized fill receipt is unavailable");
25175
- const order = this.client.program.coder.accounts.decode("orderRecord", info.data);
25176
- if (order.maker.equals(this.client.options.maker) && order.market.equals(this.client.marketAddress) && "trade" in order.kind && "filled" in order.status) {
25683
+ const order2 = this.client.program.coder.accounts.decode("orderRecord", info.data);
25684
+ if (order2.maker.equals(this.client.options.maker) && order2.market.equals(this.client.marketAddress) && "trade" in order2.kind && "filled" in order2.status) {
25177
25685
  fills.push({ id: batch[index], ...orders.get(batch[index]) });
25178
25686
  }
25179
25687
  });
@@ -25430,52 +25938,79 @@ class QuoteHandle {
25430
25938
  }
25431
25939
  async cancel() {
25432
25940
  const snapshot = await this.status();
25941
+ if (["cancelled", "filled", "rejected", "releasing"].includes(snapshot.status))
25942
+ return snapshot;
25433
25943
  const actor = this.client.options.wallet.publicKey;
25434
25944
  const grant = actor.equals(this.client.options.maker) ? undefined : this.client.grantAddress();
25435
25945
  if (snapshot.status === "validating" || snapshot.status === "validated") {
25436
- await this.client.program.methods.cancelPreparedQuote().accountsPartial({
25946
+ return this.cancelStep(() => this.client.program.methods.cancelPreparedQuote().accountsPartial({
25437
25947
  actor,
25438
25948
  grant: grant ?? this.client.program.programId,
25439
25949
  quote: this.id
25440
- }).rpc({ commitment: "confirmed" });
25441
- return this.status();
25950
+ }).rpc({ commitment: "confirmed" }), ["cancelled", "rejected"]);
25442
25951
  }
25443
25952
  if (snapshot.status === "active" || snapshot.status === "waiting") {
25444
- await this.client.program.methods.stopQuote().accountsPartial({
25953
+ await this.cancelStep(() => this.client.program.methods.stopQuote().accountsPartial({
25445
25954
  actor,
25446
25955
  market: this.client.marketAddress,
25447
25956
  quoteQueue: this.client.quoteQueueAddress,
25448
25957
  grant: grant ?? this.client.program.programId,
25449
25958
  quote: this.id
25450
- }).rpc({ commitment: "confirmed" });
25959
+ }).rpc({ commitment: "confirmed" }), ["closing", "releasing", "cancelled", "filled"]);
25451
25960
  } else if (snapshot.status !== "closing") {
25452
25961
  throw new Error("Quote cannot be cancelled in its current state");
25453
25962
  }
25454
25963
  const current = await this.status();
25455
- if (snapshot.status === "waiting")
25964
+ if (current.status !== "closing")
25456
25965
  return current;
25457
25966
  if (current.attachedOrders > 0)
25458
25967
  return current;
25968
+ const [market, makerAccount] = await Promise.all([
25969
+ this.client.read("Market", this.client.marketAddress),
25970
+ this.client.read("MarketAccount", this.client.marketAccount())
25971
+ ]);
25972
+ if (market.pendingOrders > 0 || name(makerAccount.status) !== "ready")
25973
+ return current;
25459
25974
  const offset = new anchor4.BN(randomBytes3(8), "le");
25460
25975
  const queue = await this.client.queue("release_quote", offset);
25461
- this.releaseSignature = await this.client.program.methods.releaseQuote(offset).accountsPartial({
25462
- ...queue,
25463
- payer: actor,
25464
- protocol: this.client.protocolAddress,
25465
- market: this.client.marketAddress,
25466
- marketAccount: this.client.marketAccount(),
25467
- grant: grant ?? this.client.program.programId,
25468
- quote: this.id
25469
- }).rpc({ commitment: "confirmed" });
25976
+ return this.cancelStep(async () => {
25977
+ this.releaseSignature = await this.client.program.methods.releaseQuote(offset).accountsPartial({
25978
+ ...queue,
25979
+ payer: actor,
25980
+ protocol: this.client.protocolAddress,
25981
+ market: this.client.marketAddress,
25982
+ marketAccount: this.client.marketAccount(),
25983
+ grant: grant ?? this.client.program.programId,
25984
+ quote: this.id
25985
+ }).rpc({ commitment: "confirmed" });
25986
+ }, ["releasing", "cancelled", "filled"]);
25987
+ }
25988
+ async cancelStep(submit, completed) {
25989
+ try {
25990
+ await submit();
25991
+ } catch (error) {
25992
+ const snapshot = await this.status();
25993
+ if (completed.includes(snapshot.status))
25994
+ return snapshot;
25995
+ throw error;
25996
+ }
25470
25997
  return this.status();
25471
25998
  }
25999
+ async close() {
26000
+ if (!this.client.options.wallet.publicKey.equals(this.client.options.maker))
26001
+ throw new Error("Only the maker owner can reclaim quote rent");
26002
+ const snapshot = await this.status();
26003
+ if (!["cancelled", "filled", "rejected"].includes(snapshot.status) || snapshot.attachedOrders > 0)
26004
+ throw new Error("Release the quote and settle its orders before closing");
26005
+ return this.client.program.methods.closeQuote().accountsPartial({ maker: this.client.options.maker, quote: this.id }).rpc({ commitment: "confirmed" });
26006
+ }
25472
26007
  }
25473
26008
 
25474
26009
  // src/quote/replacement.ts
25475
26010
  import * as anchor5 from "@anchor-lang/core";
25476
26011
  import { DEPTH_PROGRAM_ID as DEPTH_PROGRAM_ID3 } from "@depthhq/bindings";
25477
- import { PublicKey as PublicKey4 } from "@solana/web3.js";
25478
- import { Buffer as Buffer5 } from "buffer";
26012
+ import { PublicKey as PublicKey6 } from "@solana/web3.js";
26013
+ import { Buffer as Buffer7 } from "buffer";
25479
26014
 
25480
26015
  class QuoteReplacement {
25481
26016
  client;
@@ -25489,9 +26024,9 @@ class QuoteReplacement {
25489
26024
  if (nonce < 0n || nonce > (1n << 64n) - 1n) {
25490
26025
  throw new RangeError("clientNonce must be an unsigned 64-bit bigint");
25491
26026
  }
25492
- const bytes = new anchor5.BN(nonce.toString()).toArrayLike(Buffer5, "le", 8);
25493
- this.nextId = PublicKey4.findProgramAddressSync([
25494
- Buffer5.from("quote"),
26027
+ const bytes = new anchor5.BN(nonce.toString()).toArrayLike(Buffer7, "le", 8);
26028
+ this.nextId = PublicKey6.findProgramAddressSync([
26029
+ Buffer7.from("quote"),
25495
26030
  client.marketAddress.toBuffer(),
25496
26031
  client.options.maker.toBuffer(),
25497
26032
  bytes
@@ -25515,17 +26050,7 @@ class QuoteReplacement {
25515
26050
  phase: next?.status === "active" || next?.status === "filled" ? "active" : next?.status === "rejected" ? "failed" : next ? "publishing" : stopped ? "ready" : "stopping"
25516
26051
  };
25517
26052
  }
25518
- async resume(input, options = {}) {
25519
- if (input.clientNonce !== undefined && input.clientNonce !== this.nonce) {
25520
- throw new Error("Replacement terms use a different client nonce");
25521
- }
25522
- const timeoutMs = options.timeoutMs ?? 60000;
25523
- const pollMs = options.pollMs ?? 1000;
25524
- if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 0 || !Number.isSafeInteger(pollMs) || pollMs < 100) {
25525
- throw new RangeError("Replacement timeout or polling interval is invalid");
25526
- }
25527
- const deadline = Date.now() + timeoutMs;
25528
- const previous = this.client.quote.get(this.priorId);
26053
+ async begin() {
25529
26054
  const prior = await this.client.quoteState(this.priorId);
25530
26055
  const recorded = prior.replacementNonce == null ? undefined : BigInt(prior.replacementNonce.toString());
25531
26056
  if (recorded !== undefined && recorded !== this.nonce) {
@@ -25539,6 +26064,17 @@ class QuoteReplacement {
25539
26064
  quote: this.priorId
25540
26065
  }).rpc({ commitment: "confirmed" });
25541
26066
  }
26067
+ }
26068
+ async resume(input, options = {}) {
26069
+ if (input.clientNonce !== undefined && input.clientNonce !== this.nonce)
26070
+ throw new Error("Replacement terms use a different client nonce");
26071
+ const timeoutMs = options.timeoutMs ?? 60000;
26072
+ const pollMs = options.pollMs ?? 1000;
26073
+ if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 0 || !Number.isSafeInteger(pollMs) || pollMs < 100)
26074
+ throw new RangeError("Replacement timeout or polling interval is invalid");
26075
+ const deadline = Date.now() + timeoutMs;
26076
+ const previous = this.client.quote.get(this.priorId);
26077
+ await this.begin();
25542
26078
  for (;; ) {
25543
26079
  const snapshot = await previous.status();
25544
26080
  if (["cancelled", "filled"].includes(snapshot.status))
@@ -25564,7 +26100,7 @@ class QuoteReplacement {
25564
26100
 
25565
26101
  // src/client/client.ts
25566
26102
  function pda(seeds) {
25567
- return PublicKey5.findProgramAddressSync(seeds, DEPTH_PROGRAM_ID4)[0];
26103
+ return PublicKey7.findProgramAddressSync(seeds, DEPTH_PROGRAM_ID4)[0];
25568
26104
  }
25569
26105
  function u642(value, name2) {
25570
26106
  if (typeof value !== "bigint" || value < 0n || value > (1n << 64n) - 1n) {
@@ -25575,12 +26111,25 @@ function u642(value, name2) {
25575
26111
  function offset() {
25576
26112
  return new anchor6.BN(randomBytes3(8), "le");
25577
26113
  }
26114
+ async function retryQuote(action, deadline) {
26115
+ for (;; ) {
26116
+ try {
26117
+ return await action();
26118
+ } catch (error) {
26119
+ if (!(error instanceof anchor6.AnchorError) || error.error.errorCode.code !== "WrongMarketAccountStatus" || Date.now() >= deadline)
26120
+ throw error;
26121
+ await new Promise((resolve) => setTimeout(resolve, 1000));
26122
+ }
26123
+ }
26124
+ }
25578
26125
  function stateName(value) {
25579
26126
  return Object.keys(value)[0] ?? "unknown";
25580
26127
  }
25581
26128
 
25582
26129
  class MakerClient {
25583
26130
  options;
26131
+ hedges;
26132
+ automation;
25584
26133
  provider;
25585
26134
  program;
25586
26135
  position;
@@ -25608,6 +26157,8 @@ class MakerClient {
25608
26157
  }
25609
26158
  constructor(options) {
25610
26159
  this.options = options;
26160
+ this.hedges = new MakerAccess(options);
26161
+ this.automation = new MakerAutomation(this);
25611
26162
  this.provider = new DepthProvider(options.connection, options.wallet, {
25612
26163
  commitment: "confirmed",
25613
26164
  preflightCommitment: "confirmed"
@@ -25617,7 +26168,7 @@ class MakerClient {
25617
26168
  this.backstop = Object.assign((id) => new BackstopHandle(id, this), { offer: (input) => BackstopHandle.offer(this, input) });
25618
26169
  }
25619
26170
  static async create(options) {
25620
- const appId = typeof options.appId === "string" ? new PublicKey5(options.appId) : options.appId;
26171
+ const appId = typeof options.appId === "string" ? new PublicKey7(options.appId) : options.appId;
25621
26172
  if (options.maker && options.makerOwner && !options.maker.equals(options.makerOwner)) {
25622
26173
  throw new Error("maker and makerOwner identify different accounts");
25623
26174
  }
@@ -25661,21 +26212,21 @@ class MakerClient {
25661
26212
  openMarket: async () => this.funding.openMarket(),
25662
26213
  summary: async () => (await this.owned()).account.summary(),
25663
26214
  pending: async () => (await this.owned()).account.pending(),
25664
- deposit: async (sourceOrAmount, amount, clientNonce) => {
25665
- if (sourceOrAmount instanceof PublicKey5) {
25666
- if (amount === undefined || clientNonce === undefined)
26215
+ deposit: async (sourceOrAmount, amount3, clientNonce) => {
26216
+ if (sourceOrAmount instanceof PublicKey7) {
26217
+ if (amount3 === undefined || clientNonce === undefined)
25667
26218
  throw new RangeError("Source deposits require amount and nonce");
25668
- return this.funding.deposit(sourceOrAmount, amount, clientNonce);
26219
+ return this.funding.deposit(sourceOrAmount, amount3, clientNonce);
25669
26220
  }
25670
26221
  return (await this.owned()).account.deposit(sourceOrAmount);
25671
26222
  },
25672
26223
  withdrawalHandle: (clientNonce) => this.funding.withdrawalHandle(clientNonce),
25673
26224
  depositHandle: (nonce) => this.funding.depositHandle(nonce),
25674
- withdraw: async (destinationOrAmount, amount, clientNonce) => {
25675
- if (destinationOrAmount instanceof PublicKey5) {
25676
- if (amount === undefined || clientNonce === undefined)
26225
+ withdraw: async (destinationOrAmount, amount3, clientNonce) => {
26226
+ if (destinationOrAmount instanceof PublicKey7) {
26227
+ if (amount3 === undefined || clientNonce === undefined)
25677
26228
  throw new RangeError("Destination withdrawals require amount and nonce");
25678
- return this.funding.withdraw(destinationOrAmount, amount, clientNonce);
26229
+ return this.funding.withdraw(destinationOrAmount, amount3, clientNonce);
25679
26230
  }
25680
26231
  return (await this.owned()).account.withdraw(destinationOrAmount);
25681
26232
  },
@@ -25697,21 +26248,21 @@ class MakerClient {
25697
26248
  };
25698
26249
  marketAccount() {
25699
26250
  return pda([
25700
- Buffer6.from("market-account"),
26251
+ Buffer8.from("market-account"),
25701
26252
  this.marketAddress.toBuffer(),
25702
26253
  this.options.maker.toBuffer()
25703
26254
  ]);
25704
26255
  }
25705
26256
  grantAddress(operator = this.options.wallet.publicKey) {
25706
26257
  return pda([
25707
- Buffer6.from("operator"),
26258
+ Buffer8.from("operator"),
25708
26259
  this.marketAddress.toBuffer(),
25709
26260
  this.options.maker.toBuffer(),
25710
26261
  operator.toBuffer()
25711
26262
  ]);
25712
26263
  }
25713
- async read(name2, address3) {
25714
- const info = await this.options.connection.getAccountInfo(address3, "confirmed");
26264
+ async read(name2, address3, commitment = "confirmed") {
26265
+ const info = await this.options.connection.getAccountInfo(address3, commitment);
25715
26266
  if (!info || !info.owner.equals(DEPTH_PROGRAM_ID4)) {
25716
26267
  throw new Error(`${name2} account is unavailable`);
25717
26268
  }
@@ -25795,74 +26346,76 @@ class MakerClient {
25795
26346
  replacement: (prior, clientNonce) => new QuoteReplacement(this, prior, clientNonce),
25796
26347
  publish: async (request) => {
25797
26348
  const clientNonce = request.clientNonce ?? BigInt(new anchor6.BN(randomBytes3(8), "le").toString());
25798
- const quoteNonce = u642(clientNonce, "clientNonce");
25799
- const id = pda([
25800
- Buffer6.from("quote"),
25801
- this.marketAddress.toBuffer(),
25802
- this.options.maker.toBuffer(),
25803
- quoteNonce.toArrayLike(Buffer6, "le", 8)
25804
- ]);
25805
- if (await this.options.connection.getAccountInfo(id, "confirmed")) {
25806
- const existing = await this.quoteState(id);
25807
- if (BigInt(existing.capacity.toString()) !== request.maxCapacity || "expiresAt" in request && existing.expiry.toNumber() !== request.expiresAt) {
25808
- throw new Error("Quote nonce is already bound to different public terms");
25809
- }
25810
- return this.quote.get(id);
25811
- }
25812
26349
  const readyDeadline = Date.now() + 60000;
25813
- for (;; ) {
25814
- const account = await this.read("MarketAccount", this.marketAccount());
25815
- if (stateName(account.status) === "ready")
25816
- break;
25817
- if (Date.now() >= readyDeadline) {
25818
- throw new Error("Maker account is processing another operation");
25819
- }
25820
- await new Promise((resolve) => setTimeout(resolve, 1000));
25821
- }
25822
- const market = await this.read("Market", this.marketAddress);
25823
- const input = "tiers" in request ? request : this.flatQuote(request, market, clientNonce);
25824
- this.validateQuote(input, market);
25825
- const grant = await this.grantFor(input.maxCapacity, input.expiresAt);
25826
- const mxePublicKey = await getMXEPublicKey(this.provider, DEPTH_PROGRAM_ID4);
25827
- if (!mxePublicKey)
25828
- throw new Error("MXE public key is unavailable");
25829
- const secret = x25519.utils.randomSecretKey();
25830
- const inputKey = x25519.getPublicKey(secret);
25831
- const inputNonce = randomBytes3(16);
25832
- const cipher = new RescueCipher(x25519.getSharedSecret(secret, mxePublicKey));
25833
- const bid = Array.from({ length: 4 }, (_, i) => input.tiers[i]?.bidE8 ?? 0n);
25834
- const ask = Array.from({ length: 4 }, (_, i) => input.tiers[i]?.askE8 ?? 0n);
25835
- const reciprocal = (price) => {
25836
- if (price === 0n)
25837
- return 0n;
25838
- if (price < 100000000n)
25839
- throw new RangeError("SOL quote prices must be at least $1");
25840
- return (1n << 76n) / price;
25841
- };
25842
- const ciphertexts = cipher.encrypt(packQuoteCurve({
25843
- bid,
25844
- ask,
25845
- bidReciprocal: bid.map(reciprocal),
25846
- askReciprocal: ask.map(reciprocal)
25847
- }), inputNonce);
25848
- const computationOffset = offset();
25849
- const queue = await this.queue("prepare_quote", computationOffset);
25850
- const signature = await this.program.methods.submitQuote(computationOffset, quoteNonce, u642(input.maxCapacity, "maxCapacity"), input.tiers.length, new anchor6.BN(input.expiresAt), market.revision, market.oracleTimestamp, ciphertexts, Array.from(inputKey), new anchor6.BN(inputNonce, "le")).accountsPartial({
25851
- ...queue,
25852
- payer: this.options.wallet.publicKey,
25853
- market: this.marketAddress,
25854
- marketAccount: this.marketAccount(),
25855
- grant: grant ?? this.program.programId,
25856
- quote: id
25857
- }).rpc({ commitment: "confirmed" });
25858
- return new QuoteHandle(id, signature, this);
26350
+ return retryQuote(async () => {
26351
+ const quoteNonce = u642(clientNonce, "clientNonce");
26352
+ const id = pda([
26353
+ Buffer8.from("quote"),
26354
+ this.marketAddress.toBuffer(),
26355
+ this.options.maker.toBuffer(),
26356
+ quoteNonce.toArrayLike(Buffer8, "le", 8)
26357
+ ]);
26358
+ if (await this.options.connection.getAccountInfo(id, "confirmed")) {
26359
+ const existing = await this.quoteState(id);
26360
+ if (BigInt(existing.capacity.toString()) !== request.maxCapacity || "expiresAt" in request && existing.expiry.toNumber() !== request.expiresAt) {
26361
+ throw new Error("Quote nonce is already bound to different public terms");
26362
+ }
26363
+ return this.quote.get(id);
26364
+ }
26365
+ for (;; ) {
26366
+ const account = await this.read("MarketAccount", this.marketAccount());
26367
+ if (stateName(account.status) === "ready")
26368
+ break;
26369
+ if (Date.now() >= readyDeadline) {
26370
+ throw new Error("Maker account is processing another operation");
26371
+ }
26372
+ await new Promise((resolve) => setTimeout(resolve, 1000));
26373
+ }
26374
+ const market = await this.read("Market", this.marketAddress);
26375
+ const input = "tiers" in request ? request : this.flatQuote(request, market, clientNonce);
26376
+ this.validateQuote(input, market);
26377
+ const grant = await this.grantFor(input.maxCapacity, input.expiresAt);
26378
+ const mxePublicKey = await getMXEPublicKey(this.provider, DEPTH_PROGRAM_ID4);
26379
+ if (!mxePublicKey)
26380
+ throw new Error("MXE public key is unavailable");
26381
+ const secret = x25519.utils.randomSecretKey();
26382
+ const inputKey = x25519.getPublicKey(secret);
26383
+ const inputNonce = randomBytes3(16);
26384
+ const cipher = new RescueCipher(x25519.getSharedSecret(secret, mxePublicKey));
26385
+ const bid = Array.from({ length: 4 }, (_, i) => input.tiers[i]?.bidE8 ?? 0n);
26386
+ const ask = Array.from({ length: 4 }, (_, i) => input.tiers[i]?.askE8 ?? 0n);
26387
+ const reciprocal = (price) => {
26388
+ if (price === 0n)
26389
+ return 0n;
26390
+ if (price < 100000000n)
26391
+ throw new RangeError("SOL quote prices must be at least $1");
26392
+ return (1n << 76n) / price;
26393
+ };
26394
+ const ciphertexts = cipher.encrypt(packQuoteCurve({
26395
+ bid,
26396
+ ask,
26397
+ bidReciprocal: bid.map(reciprocal),
26398
+ askReciprocal: ask.map(reciprocal)
26399
+ }), inputNonce);
26400
+ const computationOffset = offset();
26401
+ const queue = await this.queue("prepare_quote", computationOffset);
26402
+ const signature = await this.program.methods.submitQuote(computationOffset, quoteNonce, u642(input.maxCapacity, "maxCapacity"), input.tiers.length, new anchor6.BN(input.expiresAt), market.revision, market.oracleTimestamp, ciphertexts, Array.from(inputKey), new anchor6.BN(inputNonce, "le")).accountsPartial({
26403
+ ...queue,
26404
+ payer: this.options.wallet.publicKey,
26405
+ market: this.marketAddress,
26406
+ marketAccount: this.marketAccount(),
26407
+ grant: grant ?? this.program.programId,
26408
+ quote: id
26409
+ }).rpc({ commitment: "confirmed" });
26410
+ return new QuoteHandle(id, signature, this);
26411
+ }, readyDeadline);
25859
26412
  },
25860
26413
  get: (id) => new QuoteHandle(id, undefined, this),
25861
26414
  list: async (options = {}) => {
25862
26415
  const limit = options.limit ?? 20;
25863
26416
  if (!Number.isSafeInteger(limit) || limit < 1 || limit > 100)
25864
26417
  throw new RangeError("limit must be an integer from 1 to 100");
25865
- const cursor = options.cursor ? new PublicKey5(options.cursor).toBase58() : undefined;
26418
+ const cursor = options.cursor ? new PublicKey7(options.cursor).toBase58() : undefined;
25866
26419
  const accounts2 = await this.options.connection.getProgramAccounts(DEPTH_PROGRAM_ID4, {
25867
26420
  commitment: "confirmed",
25868
26421
  dataSlice: { offset: 0, length: 0 },
@@ -25893,10 +26446,10 @@ class MakerClient {
25893
26446
  throw new Error("Quote changed during discovery");
25894
26447
  const quote = this.program.coder.accounts.decode("quoteRecord", info.data);
25895
26448
  const canonical = pda([
25896
- Buffer6.from("quote"),
26449
+ Buffer8.from("quote"),
25897
26450
  this.marketAddress.toBuffer(),
25898
26451
  this.options.maker.toBuffer(),
25899
- quote.nonce.toArrayLike(Buffer6, "le", 8)
26452
+ quote.nonce.toArrayLike(Buffer8, "le", 8)
25900
26453
  ]);
25901
26454
  if (!id.equals(canonical) || !quote.maker.equals(this.options.maker) || !quote.market.equals(this.marketAddress))
25902
26455
  throw new Error("Quote identity changed during discovery");
@@ -25966,9 +26519,9 @@ class MakerClient {
25966
26519
  const grant = await this.viewGrant();
25967
26520
  const viewNonce = offset();
25968
26521
  const view = pda([
25969
- Buffer6.from("market-view"),
26522
+ Buffer8.from("market-view"),
25970
26523
  this.marketAccount().toBuffer(),
25971
- viewNonce.toArrayLike(Buffer6, "le", 8)
26524
+ viewNonce.toArrayLike(Buffer8, "le", 8)
25972
26525
  ]);
25973
26526
  return this.requestView("market", view, viewNonce, {
25974
26527
  market: this.marketAddress,
@@ -25976,21 +26529,21 @@ class MakerClient {
25976
26529
  grant: grant ?? null
25977
26530
  });
25978
26531
  }
25979
- async requestFillView(order) {
25980
- const state = await this.read("OrderRecord", order);
26532
+ async requestFillView(order2) {
26533
+ const state = await this.read("OrderRecord", order2);
25981
26534
  if (!state.maker.equals(this.options.maker) || !state.market.equals(this.marketAddress) || stateName(state.status) !== "filled" || stateName(state.kind) !== "trade") {
25982
26535
  throw new Error("Fill is not a finalized trade by this maker");
25983
26536
  }
25984
26537
  const grant = await this.viewGrant();
25985
26538
  const viewNonce = offset();
25986
26539
  const view = pda([
25987
- Buffer6.from("fill-view"),
25988
- order.toBuffer(),
26540
+ Buffer8.from("fill-view"),
26541
+ order2.toBuffer(),
25989
26542
  this.options.wallet.publicKey.toBuffer(),
25990
- viewNonce.toArrayLike(Buffer6, "le", 8)
26543
+ viewNonce.toArrayLike(Buffer8, "le", 8)
25991
26544
  ]);
25992
26545
  return this.requestView("fill", view, viewNonce, {
25993
- order,
26546
+ order: order2,
25994
26547
  grant: grant ?? null
25995
26548
  });
25996
26549
  }
@@ -26001,10 +26554,10 @@ class MakerClient {
26001
26554
  const grant = await this.viewGrant();
26002
26555
  const viewNonce = offset();
26003
26556
  const view = pda([
26004
- Buffer6.from("quote-view"),
26557
+ Buffer8.from("quote-view"),
26005
26558
  quote.toBuffer(),
26006
26559
  this.options.wallet.publicKey.toBuffer(),
26007
- viewNonce.toArrayLike(Buffer6, "le", 8)
26560
+ viewNonce.toArrayLike(Buffer8, "le", 8)
26008
26561
  ]);
26009
26562
  return this.requestView("quote", view, viewNonce, {
26010
26563
  market: this.marketAddress,
@@ -26036,8 +26589,8 @@ class MakerClient {
26036
26589
  const actions = {
26037
26590
  id: address3,
26038
26591
  cancelOpen: () => this.funding.cancelOpenMarket(),
26039
- addMargin: async (amount, clientNonce) => (await this.owned()).position.addMargin(amount, clientNonce),
26040
- removeMargin: async (amount, clientNonce) => (await this.owned()).position.removeMargin(amount, clientNonce),
26592
+ addMargin: async (amount3, clientNonce) => (await this.owned()).position.addMargin(amount3, clientNonce),
26593
+ removeMargin: async (amount3, clientNonce) => (await this.owned()).position.removeMargin(amount3, clientNonce),
26041
26594
  summary: async (options = { timeoutMs: 30000 }) => {
26042
26595
  const view = await this.requestMarketView();
26043
26596
  const result = await view.wait(options);
@@ -26057,7 +26610,7 @@ class MakerClient {
26057
26610
  const store = createCursorStore(genesis, this.options.maker.toBase58(), this.options.cursorDirectory);
26058
26611
  const cursor = await store.load();
26059
26612
  return new FillHistory(this).subscribe(async (fill) => {
26060
- const execution = await this.fills.get(new PublicKey5(fill.id));
26613
+ const execution = await this.fills.get(new PublicKey7(fill.id));
26061
26614
  if (execution.status !== "ready")
26062
26615
  throw new Error(`Private maker fill ${fill.id} is ${execution.status}`);
26063
26616
  await options.onFill({ ...fill, execution });
@@ -26068,8 +26621,8 @@ class MakerClient {
26068
26621
  onError: options.onError
26069
26622
  });
26070
26623
  },
26071
- get: async (order, options = { timeoutMs: 30000 }) => {
26072
- const view = await this.requestFillView(order);
26624
+ get: async (order2, options = { timeoutMs: 30000 }) => {
26625
+ const view = await this.requestFillView(order2);
26073
26626
  const result = await view.wait(options);
26074
26627
  if (result.status !== "pending")
26075
26628
  await view.close();
@@ -26110,12 +26663,67 @@ class MakerClient {
26110
26663
  async function createDepthMaker(options) {
26111
26664
  return MakerClient.create(options);
26112
26665
  }
26666
+ // src/hedge/wallet.ts
26667
+ async function connect_hyperliquid(provider) {
26668
+ const accounts2 = await provider.request({ method: "eth_requestAccounts" });
26669
+ if (!Array.isArray(accounts2) || typeof accounts2[0] !== "string" || !/^0x[0-9a-fA-F]{40}$/.test(accounts2[0]))
26670
+ throw new Error("The Ethereum wallet did not provide an account");
26671
+ const address3 = accounts2[0];
26672
+ const check = async () => {
26673
+ const current = await provider.request({ method: "eth_accounts" });
26674
+ if (!Array.isArray(current) || typeof current[0] !== "string" || current[0].toLowerCase() !== address3.toLowerCase())
26675
+ throw new Error("The Ethereum wallet account changed; connect it again");
26676
+ };
26677
+ return {
26678
+ async getAddresses() {
26679
+ await check();
26680
+ return [address3];
26681
+ },
26682
+ async getChainId() {
26683
+ const chain = await provider.request({ method: "eth_chainId" });
26684
+ if (typeof chain !== "string" || !/^0x[0-9a-fA-F]+$/.test(chain) || !Number.isSafeInteger(Number(chain)))
26685
+ throw new Error("Ethereum wallet chain is invalid");
26686
+ return Number(chain);
26687
+ },
26688
+ async signTypedData(params) {
26689
+ await check();
26690
+ const signature = await provider.request({
26691
+ method: "eth_signTypedData_v4",
26692
+ params: [
26693
+ address3,
26694
+ JSON.stringify({
26695
+ ...params,
26696
+ types: {
26697
+ EIP712Domain: [
26698
+ { name: "name", type: "string" },
26699
+ { name: "version", type: "string" },
26700
+ { name: "chainId", type: "uint256" },
26701
+ { name: "verifyingContract", type: "address" }
26702
+ ],
26703
+ ...params.types
26704
+ }
26705
+ })
26706
+ ]
26707
+ });
26708
+ if (typeof signature !== "string" || !/^0x[0-9a-fA-F]{130}$/.test(signature))
26709
+ throw new Error("Ethereum wallet returned an invalid signature");
26710
+ return signature;
26711
+ }
26712
+ };
26713
+ }
26113
26714
  export {
26715
+ setup_hyperliquid,
26114
26716
  createDepthMaker as create_depth_maker,
26115
26717
  createDepthMaker,
26718
+ connect_hyperliquid,
26719
+ automationWire,
26720
+ automationView,
26721
+ automationConfig,
26116
26722
  QuoteReplacement,
26117
26723
  QuoteHandle,
26118
26724
  MakerClient,
26725
+ MakerAutomation,
26726
+ MakerAccess,
26119
26727
  BackstopRelease,
26120
26728
  BackstopHandle
26121
26729
  };