@hyperbridge/simplex 0.16.5 → 0.16.6

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.
@@ -318650,10 +318650,16 @@ var CANCEL_ORDER_MUTATION = `
318650
318650
  `;
318651
318651
  var OrderbookRequestError2 = class extends Error {
318652
318652
  };
318653
+ function graphqlEndpoint(url2) {
318654
+ const trimmed = url2.trim();
318655
+ if (trimmed.includes("?")) return trimmed;
318656
+ const withoutTrailingSlash = trimmed.replace(/\/+$/, "");
318657
+ return withoutTrailingSlash.endsWith("/graphql") ? withoutTrailingSlash : `${withoutTrailingSlash}/graphql`;
318658
+ }
318653
318659
  var OrderbookClient = class {
318654
318660
  constructor(url2, requestTimeoutMs, loggers = defaultLoggerContext()) {
318655
- this.url = url2;
318656
318661
  this.requestTimeoutMs = requestTimeoutMs;
318662
+ this.url = graphqlEndpoint(url2);
318657
318663
  this.logger = loggers.get("orderbook");
318658
318664
  }
318659
318665
  /** The limits to validate against before posting, plus the books on offer. */
@@ -318751,7 +318757,9 @@ var OrderbookClient = class {
318751
318757
  clearTimeout(timer);
318752
318758
  }
318753
318759
  if (!response.ok) {
318754
- throw new OrderbookRequestError2(`Orderbook returned HTTP ${response.status} ${response.statusText}`);
318760
+ throw new OrderbookRequestError2(
318761
+ `Orderbook at ${this.url} returned HTTP ${response.status} ${response.statusText}`
318762
+ );
318755
318763
  }
318756
318764
  const body = await response.json().catch((err) => {
318757
318765
  throw new OrderbookRequestError2(`Orderbook returned a body that is not JSON: ${describe(err)}`);
@@ -318870,7 +318878,7 @@ var HEARTBEAT_TYPES = {
318870
318878
  var LimitOrderValidationError = class extends Error {
318871
318879
  };
318872
318880
  var LimitOrderService = class {
318873
- constructor(store, client, contractService, configService, assetRegistry, signer, defaultTtlSecs, delegationService, loggers = defaultLoggerContext(), startingNonce = initialOrderNonce) {
318881
+ constructor(store, client, contractService, configService, assetRegistry, signer, defaultTtlSecs, delegationService, loggers = defaultLoggerContext(), startingNonce = initialOrderNonce, vaultBalances) {
318874
318882
  this.store = store;
318875
318883
  this.client = client;
318876
318884
  this.contractService = contractService;
@@ -318880,6 +318888,7 @@ var LimitOrderService = class {
318880
318888
  this.defaultTtlSecs = defaultTtlSecs;
318881
318889
  this.delegationService = delegationService;
318882
318890
  this.startingNonce = startingNonce;
318891
+ this.vaultBalances = vaultBalances;
318883
318892
  this.logger = loggers.get("limit-orders");
318884
318893
  }
318885
318894
  /**
@@ -319015,6 +319024,16 @@ var LimitOrderService = class {
319015
319024
  throw err;
319016
319025
  }
319017
319026
  }
319027
+ /**
319028
+ * The pairs an order can be written against, and the smallest payout each token may carry.
319029
+ *
319030
+ * The orderbook lists the books; `resolveBook` refuses a request naming anything else, so the
319031
+ * operator is offered exactly these and no combination of symbols they could not post.
319032
+ */
319033
+ async books() {
319034
+ const limits = await this.limits();
319035
+ return { books: limits.books, minOrderSizes: limits.serverInfo.minOrderSizes };
319036
+ }
319018
319037
  /**
319019
319038
  * Reads `serverInfo` and `books`, reusing the last read for {@link LIMITS_TTL_MS}.
319020
319039
  *
@@ -319122,28 +319141,61 @@ var LimitOrderService = class {
319122
319141
  * balance on the fill chain, so the operator hears it while they are creating
319123
319142
  * the order.
319124
319143
  *
319144
+ * A fill pays out of the wallet and then withdraws any shortfall from the
319145
+ * configured ERC-4626 vaults in the same batch, so what those vaults hold of
319146
+ * the payout token backs the order too and is counted here. Without it an
319147
+ * operator who sweeps inventory into a vault is refused orders their filler
319148
+ * would have filled.
319149
+ *
319125
319150
  * Each order is checked against the whole balance, not against what is left of
319126
319151
  * it after the others. One balance backs every order resting on it — that is
319127
319152
  * what quoting both sides of a book is — and the orderbook says as much: it
319128
319153
  * advertises each entry at `min(quoted, balance)` rather than dividing the
319129
319154
  * balance between them. Whichever order fills first draws the inventory down,
319130
319155
  * and the rest are cut to what is left. Netting them here would refuse the
319131
- * second side of every book.
319156
+ * second side of every book. Vault positions are counted the same way: the
319157
+ * whole position, not what is left after reservations for fills in flight.
319132
319158
  */
319133
319159
  async assertWalletCanPay(symbol3, chain2, payout) {
319134
319160
  const token = this.assetRegistry.getAddress(symbol3, chain2);
319135
319161
  if (!token) return;
319136
319162
  const decimals = await this.decimalsFor(symbol3, token, chain2);
319137
- const balance = toScaled(
319163
+ const wallet = toScaled(
319138
319164
  await this.contractService.getTokenBalance(chain2, token, this.signer.address),
319139
319165
  decimals
319140
319166
  );
319141
- if (balance < payout) {
319167
+ const vaults = await this.vaultHoldings(token, chain2);
319168
+ if (wallet + vaults < payout) {
319169
+ const held = vaults > 0n ? `${toHuman(wallet)} in the wallet and ${toHuman(vaults)} in vaults` : toHuman(wallet);
319142
319170
  throw new LimitOrderValidationError(
319143
- `The wallet holds ${toHuman(balance)} ${symbol3} on ${chain2}, which cannot pay out ${toHuman(payout)}`
319171
+ `The wallet holds ${held} ${symbol3} on ${chain2}, which cannot pay out ${toHuman(payout)}`
319144
319172
  );
319145
319173
  }
319146
319174
  }
319175
+ /**
319176
+ * What the configured vaults hold of `token` on `chain`, in scaled units.
319177
+ *
319178
+ * Zero when no vault is configured. A snapshot that cannot be read is also
319179
+ * zero: the wallet alone then has to cover the order, which refuses one the
319180
+ * filler might have managed rather than accepting one it could not.
319181
+ */
319182
+ async vaultHoldings(token, chain2) {
319183
+ if (!this.vaultBalances) return 0n;
319184
+ let positions;
319185
+ try {
319186
+ positions = await this.vaultBalances.getBalanceSnapshot(chain2);
319187
+ } catch (err) {
319188
+ this.logger.warn({ chain: chain2, token, err }, "Could not read vault balances; backing the order on the wallet alone");
319189
+ return 0n;
319190
+ }
319191
+ const wanted = token.toLowerCase();
319192
+ let total = 0n;
319193
+ for (const position of positions) {
319194
+ if (position.chain !== chain2 || position.asset.toLowerCase() !== wanted) continue;
319195
+ total += toScaled(position.positionAssets, position.decimals);
319196
+ }
319197
+ return total;
319198
+ }
319147
319199
  /**
319148
319200
  * Works a limit order down by what a fill delivered, and puts the rest back on
319149
319201
  * the orderbook.
@@ -321732,6 +321784,11 @@ var UiServer = class {
321732
321784
  if (method === "POST") return this.handleLimitOrderCreate(req, res);
321733
321785
  return sendJson(res, 405, { error: "Method not allowed" });
321734
321786
  }
321787
+ if (path2 === "/api/orderbook/books") {
321788
+ if (this.mode !== "operator") return sendJson(res, 409, { error: "Filler is not running" });
321789
+ if (method !== "GET") return sendJson(res, 405, { error: "Method not allowed" });
321790
+ return this.handleLimitOrders(res, () => this.operator.limitOrders.books());
321791
+ }
321735
321792
  const limitOrderMatch = path2.match(/^\/api\/limit-orders\/([\w-]+)$/);
321736
321793
  if (limitOrderMatch) {
321737
321794
  if (this.mode !== "operator") return sendJson(res, 409, { error: "Filler is not running" });
@@ -364615,7 +364672,10 @@ async function bootFiller(config5, options) {
364615
364672
  runtimeSigner,
364616
364673
  config5.orderbook.defaultTtlSecs ?? DEFAULT_LIMIT_ORDER_TTL_SECONDS,
364617
364674
  new DelegationService(chainClientManager, configService, runtimeSigner),
364618
- options.loggers
364675
+ options.loggers,
364676
+ initialOrderNonce,
364677
+ // A fill withdraws a payout shortfall from the vaults, so what they hold backs an order too.
364678
+ vaultVenue
364619
364679
  );
364620
364680
  intentFiller.setLimitOrderService(limitOrderService);
364621
364681
  const lifecycle = new LimitOrderLifecycle(
@@ -365702,6 +365762,10 @@ var LimitOrderController = class {
365702
365762
  ]);
365703
365763
  return { order, fills, bids };
365704
365764
  }
365765
+ /** The pairs the orderbook lists, and the smallest payout each token may carry. */
365766
+ books() {
365767
+ return this.service.books();
365768
+ }
365705
365769
  /** Creates the order, posts it, and reports what the orderbook made of it. */
365706
365770
  async create(request3) {
365707
365771
  const posted = await this.service.create(request3);