@hyperbridge/simplex 0.18.2 → 0.18.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1320,16 +1320,33 @@ interface BidPlan {
1320
1320
  declare class CacheService {
1321
1321
  private cacheData;
1322
1322
  private readonly CACHE_EXPIRY_MS;
1323
+ /** How long each order's source confirmations take, for the orders still waiting for them. */
1324
+ private readonly confirmationWaits;
1323
1325
  /** When each order's bid loop began, for the orders whose loop is still running. */
1324
1326
  private readonly pins;
1325
1327
  private logger;
1326
1328
  constructor(loggers?: LoggerContext);
1327
1329
  /**
1328
- * Whether an entry is still fresh. A pinned order's entries are aged as of the pin,
1329
- * so what was fresh when its bid loop began stays fresh until the loop ends, and
1330
+ * Whether an entry is still live. A pinned order's entries are judged as of the pin,
1331
+ * so what was live when its bid loop began stays live until the loop ends, and
1330
1332
  * what had already expired stays expired.
1331
1333
  */
1332
1334
  private isCacheValid;
1335
+ /**
1336
+ * When an entry written now for the order expires: `CACHE_EXPIRY_MS` from now, plus the
1337
+ * time the order's source confirmations take while it waits for them.
1338
+ */
1339
+ private expiresAt;
1340
+ /**
1341
+ * Lets what is cached for the order outlive `CACHE_EXPIRY_MS` by `waitMs`, the time its
1342
+ * source confirmations take, and returns the release.
1343
+ *
1344
+ * An order is evaluated while it waits for its confirmations, and its bids are signed after
1345
+ * them from what the evaluation cached, so that has to outlast the wait. Each entry takes
1346
+ * its expiry when it is written: the release does not shorten what is already cached, it
1347
+ * only stops later entries from getting the extra time.
1348
+ */
1349
+ extendForConfirmations(orderId: string, waitMs: number): () => void;
1333
1350
  /**
1334
1351
  * Keeps the order's evaluation alive while its bids go out, and returns the release.
1335
1352
  *
@@ -1661,7 +1678,7 @@ declare class ContractInteractionService {
1661
1678
  * Blocks that cannot be read fall back to the declared figure, then to
1662
1679
  * {@link FALLBACK_BLOCK_TIME_SECONDS}. That answer is not kept.
1663
1680
  */
1664
- private blockTimeSeconds;
1681
+ blockTimeSeconds(chain: string): Promise<number>;
1665
1682
  /** The average block time over the chain's last {@link BLOCK_TIME_SAMPLE_BLOCKS} blocks, in seconds. */
1666
1683
  private measureBlockTimeSeconds;
1667
1684
  /**
@@ -2557,6 +2574,12 @@ declare class IntentFiller {
2557
2574
  private verifyOrderOnSource;
2558
2575
  private handleNewOrder;
2559
2576
  private evaluateOrder;
2577
+ /**
2578
+ * How long `confirmations` take on `chain`, at the block time measured when simplex started.
2579
+ * Zero when there is no block time to be had: the order then keeps the cache's own lifetime,
2580
+ * and an evaluation that expires before its bids is redone.
2581
+ */
2582
+ private confirmationWaitMs;
2560
2583
  /**
2561
2584
  * The destination chain's latest block number, the clock `order.deadline` is read on.
2562
2585
  *
package/dist/index.d.ts CHANGED
@@ -1320,16 +1320,33 @@ interface BidPlan {
1320
1320
  declare class CacheService {
1321
1321
  private cacheData;
1322
1322
  private readonly CACHE_EXPIRY_MS;
1323
+ /** How long each order's source confirmations take, for the orders still waiting for them. */
1324
+ private readonly confirmationWaits;
1323
1325
  /** When each order's bid loop began, for the orders whose loop is still running. */
1324
1326
  private readonly pins;
1325
1327
  private logger;
1326
1328
  constructor(loggers?: LoggerContext);
1327
1329
  /**
1328
- * Whether an entry is still fresh. A pinned order's entries are aged as of the pin,
1329
- * so what was fresh when its bid loop began stays fresh until the loop ends, and
1330
+ * Whether an entry is still live. A pinned order's entries are judged as of the pin,
1331
+ * so what was live when its bid loop began stays live until the loop ends, and
1330
1332
  * what had already expired stays expired.
1331
1333
  */
1332
1334
  private isCacheValid;
1335
+ /**
1336
+ * When an entry written now for the order expires: `CACHE_EXPIRY_MS` from now, plus the
1337
+ * time the order's source confirmations take while it waits for them.
1338
+ */
1339
+ private expiresAt;
1340
+ /**
1341
+ * Lets what is cached for the order outlive `CACHE_EXPIRY_MS` by `waitMs`, the time its
1342
+ * source confirmations take, and returns the release.
1343
+ *
1344
+ * An order is evaluated while it waits for its confirmations, and its bids are signed after
1345
+ * them from what the evaluation cached, so that has to outlast the wait. Each entry takes
1346
+ * its expiry when it is written: the release does not shorten what is already cached, it
1347
+ * only stops later entries from getting the extra time.
1348
+ */
1349
+ extendForConfirmations(orderId: string, waitMs: number): () => void;
1333
1350
  /**
1334
1351
  * Keeps the order's evaluation alive while its bids go out, and returns the release.
1335
1352
  *
@@ -1661,7 +1678,7 @@ declare class ContractInteractionService {
1661
1678
  * Blocks that cannot be read fall back to the declared figure, then to
1662
1679
  * {@link FALLBACK_BLOCK_TIME_SECONDS}. That answer is not kept.
1663
1680
  */
1664
- private blockTimeSeconds;
1681
+ blockTimeSeconds(chain: string): Promise<number>;
1665
1682
  /** The average block time over the chain's last {@link BLOCK_TIME_SAMPLE_BLOCKS} blocks, in seconds. */
1666
1683
  private measureBlockTimeSeconds;
1667
1684
  /**
@@ -2557,6 +2574,12 @@ declare class IntentFiller {
2557
2574
  private verifyOrderOnSource;
2558
2575
  private handleNewOrder;
2559
2576
  private evaluateOrder;
2577
+ /**
2578
+ * How long `confirmations` take on `chain`, at the block time measured when simplex started.
2579
+ * Zero when there is no block time to be had: the order then keeps the cache's own lifetime,
2580
+ * and an evaluation that expires before its bids is redone.
2581
+ */
2582
+ private confirmationWaitMs;
2560
2583
  /**
2561
2584
  * The destination chain's latest block number, the clock `order.deadline` is read on.
2562
2585
  *
package/dist/index.js CHANGED
@@ -17067,8 +17067,10 @@ function budgetFromCache(budget) {
17067
17067
  }
17068
17068
  var CacheService = class {
17069
17069
  constructor(loggers = defaultLoggerContext()) {
17070
- this.CACHE_EXPIRY_MS = 1 * 60 * 1e3;
17071
- // 1 minute
17070
+ this.CACHE_EXPIRY_MS = 5 * 60 * 1e3;
17071
+ // 5 minutes
17072
+ /** How long each order's source confirmations take, for the orders still waiting for them. */
17073
+ this.confirmationWaits = /* @__PURE__ */ new Map();
17072
17074
  /** When each order's bid loop began, for the orders whose loop is still running. */
17073
17075
  this.pins = /* @__PURE__ */ new Map();
17074
17076
  this.logger = loggers.get("cache-service");
@@ -17088,13 +17090,32 @@ var CacheService = class {
17088
17090
  };
17089
17091
  }
17090
17092
  /**
17091
- * Whether an entry is still fresh. A pinned order's entries are aged as of the pin,
17092
- * so what was fresh when its bid loop began stays fresh until the loop ends, and
17093
+ * Whether an entry is still live. A pinned order's entries are judged as of the pin,
17094
+ * so what was live when its bid loop began stays live until the loop ends, and
17093
17095
  * what had already expired stays expired.
17094
17096
  */
17095
- isCacheValid(timestamp, orderId) {
17096
- const now = (orderId !== void 0 ? this.pins.get(orderId) : void 0) ?? Date.now();
17097
- return now - timestamp < this.CACHE_EXPIRY_MS;
17097
+ isCacheValid(expiresAt, orderId) {
17098
+ return (this.pins.get(orderId) ?? Date.now()) < expiresAt;
17099
+ }
17100
+ /**
17101
+ * When an entry written now for the order expires: `CACHE_EXPIRY_MS` from now, plus the
17102
+ * time the order's source confirmations take while it waits for them.
17103
+ */
17104
+ expiresAt(orderId) {
17105
+ return Date.now() + this.CACHE_EXPIRY_MS + (this.confirmationWaits.get(orderId) ?? 0);
17106
+ }
17107
+ /**
17108
+ * Lets what is cached for the order outlive `CACHE_EXPIRY_MS` by `waitMs`, the time its
17109
+ * source confirmations take, and returns the release.
17110
+ *
17111
+ * An order is evaluated while it waits for its confirmations, and its bids are signed after
17112
+ * them from what the evaluation cached, so that has to outlast the wait. Each entry takes
17113
+ * its expiry when it is written: the release does not shorten what is already cached, it
17114
+ * only stops later entries from getting the extra time.
17115
+ */
17116
+ extendForConfirmations(orderId, waitMs) {
17117
+ this.confirmationWaits.set(orderId, waitMs);
17118
+ return () => this.confirmationWaits.delete(orderId);
17098
17119
  }
17099
17120
  /**
17100
17121
  * Keeps the order's evaluation alive while its bids go out, and returns the release.
@@ -17111,37 +17132,37 @@ var CacheService = class {
17111
17132
  return () => this.pins.delete(orderId);
17112
17133
  }
17113
17134
  cleanupStaleData() {
17114
- const staleGasEstimateIds = Object.entries(this.cacheData.gasEstimates).filter(([orderId, data]) => !this.isCacheValid(data.timestamp, orderId)).map(([orderId]) => orderId);
17135
+ const staleGasEstimateIds = Object.entries(this.cacheData.gasEstimates).filter(([orderId, data]) => !this.isCacheValid(data.expiresAt, orderId)).map(([orderId]) => orderId);
17115
17136
  staleGasEstimateIds.forEach((orderId) => {
17116
17137
  delete this.cacheData.gasEstimates[orderId];
17117
17138
  });
17118
17139
  for (const [orderId, data] of Object.entries(this.cacheData.bidPlans)) {
17119
- if (!this.isCacheValid(data.timestamp, orderId)) delete this.cacheData.bidPlans[orderId];
17140
+ if (!this.isCacheValid(data.expiresAt, orderId)) delete this.cacheData.bidPlans[orderId];
17120
17141
  }
17121
17142
  for (const [orderId, data] of Object.entries(this.cacheData.matchedLimitOrders)) {
17122
- if (!this.isCacheValid(data.timestamp, orderId)) delete this.cacheData.matchedLimitOrders[orderId];
17143
+ if (!this.isCacheValid(data.expiresAt, orderId)) delete this.cacheData.matchedLimitOrders[orderId];
17123
17144
  }
17124
- const staleSwapOperationIds = Object.entries(this.cacheData.swapOperations).filter(([orderId, data]) => !this.isCacheValid(data.timestamp, orderId)).map(([orderId]) => orderId);
17145
+ const staleSwapOperationIds = Object.entries(this.cacheData.swapOperations).filter(([orderId, data]) => !this.isCacheValid(data.expiresAt, orderId)).map(([orderId]) => orderId);
17125
17146
  staleSwapOperationIds.forEach((orderId) => {
17126
17147
  delete this.cacheData.swapOperations[orderId];
17127
17148
  });
17128
- const staleFillerOutputIds = Object.entries(this.cacheData.fillerOutputs).filter(([orderId, data]) => !this.isCacheValid(data.timestamp, orderId)).map(([orderId]) => orderId);
17149
+ const staleFillerOutputIds = Object.entries(this.cacheData.fillerOutputs).filter(([orderId, data]) => !this.isCacheValid(data.expiresAt, orderId)).map(([orderId]) => orderId);
17129
17150
  staleFillerOutputIds.forEach((orderId) => {
17130
17151
  delete this.cacheData.fillerOutputs[orderId];
17131
17152
  });
17132
- const stalePairIds = Object.entries(this.cacheData.pairClassifications).filter(([orderId, data]) => !this.isCacheValid(data.timestamp, orderId)).map(([orderId]) => orderId);
17153
+ const stalePairIds = Object.entries(this.cacheData.pairClassifications).filter(([orderId, data]) => !this.isCacheValid(data.expiresAt, orderId)).map(([orderId]) => orderId);
17133
17154
  stalePairIds.forEach((orderId) => {
17134
17155
  delete this.cacheData.pairClassifications[orderId];
17135
17156
  });
17136
- const staleFundingIds = Object.entries(this.cacheData.fundingPrepends).filter(([orderId, data]) => !this.isCacheValid(data.timestamp, orderId)).map(([orderId]) => orderId);
17157
+ const staleFundingIds = Object.entries(this.cacheData.fundingPrepends).filter(([orderId, data]) => !this.isCacheValid(data.expiresAt, orderId)).map(([orderId]) => orderId);
17137
17158
  staleFundingIds.forEach((orderId) => {
17138
17159
  delete this.cacheData.fundingPrepends[orderId];
17139
17160
  });
17140
- const stalePartialIds = Object.entries(this.cacheData.partialFills).filter(([orderId, data]) => !this.isCacheValid(data.timestamp, orderId)).map(([orderId]) => orderId);
17161
+ const stalePartialIds = Object.entries(this.cacheData.partialFills).filter(([orderId, data]) => !this.isCacheValid(data.expiresAt, orderId)).map(([orderId]) => orderId);
17141
17162
  stalePartialIds.forEach((orderId) => {
17142
17163
  delete this.cacheData.partialFills[orderId];
17143
17164
  });
17144
- const staleWaivedIds = Object.entries(this.cacheData.feeChecksWaived).filter(([orderId, data]) => !this.isCacheValid(data.timestamp, orderId)).map(([orderId]) => orderId);
17165
+ const staleWaivedIds = Object.entries(this.cacheData.feeChecksWaived).filter(([orderId, data]) => !this.isCacheValid(data.expiresAt, orderId)).map(([orderId]) => orderId);
17145
17166
  staleWaivedIds.forEach((orderId) => {
17146
17167
  delete this.cacheData.feeChecksWaived[orderId];
17147
17168
  });
@@ -17149,7 +17170,7 @@ var CacheService = class {
17149
17170
  getGasEstimate(orderId) {
17150
17171
  try {
17151
17172
  const cache = this.cacheData.gasEstimates[orderId];
17152
- if (cache && this.isCacheValid(cache.timestamp, orderId)) {
17173
+ if (cache && this.isCacheValid(cache.expiresAt, orderId)) {
17153
17174
  return {
17154
17175
  totalCostInSourceFeeToken: BigInt(cache.totalCostInSourceFeeToken),
17155
17176
  relayerFeeInSourceFeeToken: BigInt(cache.relayerFeeInSourceFeeToken ?? "0"),
@@ -17184,7 +17205,7 @@ var CacheService = class {
17184
17205
  maxFeePerGas: maxFeePerGas.toString(),
17185
17206
  maxPriorityFeePerGas: maxPriorityFeePerGas.toString(),
17186
17207
  totalGasCostWei: totalGasCostWei.toString(),
17187
- timestamp: Date.now()
17208
+ expiresAt: this.expiresAt(orderId)
17188
17209
  };
17189
17210
  } catch (error) {
17190
17211
  this.logger.error({ err: error }, "Error setting gas estimate");
@@ -17194,7 +17215,7 @@ var CacheService = class {
17194
17215
  getSwapOperations(orderId) {
17195
17216
  try {
17196
17217
  const cache = this.cacheData.swapOperations[orderId];
17197
- if (cache && this.isCacheValid(cache.timestamp, orderId)) {
17218
+ if (cache && this.isCacheValid(cache.expiresAt, orderId)) {
17198
17219
  return {
17199
17220
  calls: cache.calls,
17200
17221
  totalGasEstimate: BigInt(cache.totalGasEstimate)
@@ -17212,7 +17233,7 @@ var CacheService = class {
17212
17233
  this.cacheData.swapOperations[orderId] = {
17213
17234
  calls,
17214
17235
  totalGasEstimate: totalGasEstimate.toString(),
17215
- timestamp: Date.now()
17236
+ expiresAt: this.expiresAt(orderId)
17216
17237
  };
17217
17238
  } catch (error) {
17218
17239
  this.logger.error({ err: error }, "Error setting swap operations");
@@ -17222,7 +17243,7 @@ var CacheService = class {
17222
17243
  getFillerOutputs(orderId) {
17223
17244
  try {
17224
17245
  const cache = this.cacheData.fillerOutputs[orderId];
17225
- if (cache && this.isCacheValid(cache.timestamp, orderId)) {
17246
+ if (cache && this.isCacheValid(cache.expiresAt, orderId)) {
17226
17247
  return cache.outputs.map((o) => ({
17227
17248
  token: o.token,
17228
17249
  amount: BigInt(o.amount)
@@ -17238,7 +17259,7 @@ var CacheService = class {
17238
17259
  getFillerInputs(orderId) {
17239
17260
  try {
17240
17261
  const cache = this.cacheData.fillerOutputs[orderId];
17241
- if (cache?.inputs && this.isCacheValid(cache.timestamp, orderId)) {
17262
+ if (cache?.inputs && this.isCacheValid(cache.expiresAt, orderId)) {
17242
17263
  return cache.inputs.map((o) => ({
17243
17264
  token: o.token,
17244
17265
  amount: BigInt(o.amount)
@@ -17260,7 +17281,7 @@ var CacheService = class {
17260
17281
  getBidBudget(orderId) {
17261
17282
  try {
17262
17283
  const cache = this.cacheData.fillerOutputs[orderId];
17263
- if (cache?.budget && this.isCacheValid(cache.timestamp, orderId)) return budgetFromCache(cache.budget);
17284
+ if (cache?.budget && this.isCacheValid(cache.expiresAt, orderId)) return budgetFromCache(cache.budget);
17264
17285
  return null;
17265
17286
  } catch (error) {
17266
17287
  this.logger.error({ err: error }, "Error getting bid budget");
@@ -17280,7 +17301,7 @@ var CacheService = class {
17280
17301
  amount: o.amount.toString()
17281
17302
  })),
17282
17303
  ...budget ? { budget: budgetToCache(budget) } : {},
17283
- timestamp: Date.now()
17304
+ expiresAt: this.expiresAt(orderId)
17284
17305
  };
17285
17306
  } catch (error) {
17286
17307
  this.logger.error({ err: error }, "Error setting filler outputs");
@@ -17297,7 +17318,7 @@ var CacheService = class {
17297
17318
  getMatchedLimitOrder(orderId) {
17298
17319
  try {
17299
17320
  const cache = this.cacheData.matchedLimitOrders[orderId];
17300
- if (cache && this.isCacheValid(cache.timestamp, orderId)) {
17321
+ if (cache && this.isCacheValid(cache.expiresAt, orderId)) {
17301
17322
  return cache.holds.map((hold) => ({ limitOrderId: hold.limitOrderId, payout: BigInt(hold.payout) }));
17302
17323
  }
17303
17324
  return [];
@@ -17309,7 +17330,7 @@ var CacheService = class {
17309
17330
  getBidPlans(orderId) {
17310
17331
  try {
17311
17332
  const cache = this.cacheData.bidPlans[orderId];
17312
- if (!cache || !this.isCacheValid(cache.timestamp, orderId)) return [];
17333
+ if (!cache || !this.isCacheValid(cache.expiresAt, orderId)) return [];
17313
17334
  return cache.plans.map((plan) => ({
17314
17335
  limitOrderId: plan.limitOrderId,
17315
17336
  leg: plan.leg ?? 0,
@@ -17360,7 +17381,7 @@ var CacheService = class {
17360
17381
  ...plan.inputDecimals !== void 0 ? { inputDecimals: plan.inputDecimals } : {},
17361
17382
  ...plan.budget ? { budget: budgetToCache(plan.budget) } : {}
17362
17383
  })),
17363
- timestamp: Date.now()
17384
+ expiresAt: this.expiresAt(orderId)
17364
17385
  };
17365
17386
  } catch (error) {
17366
17387
  this.logger.error({ err: error }, "Error setting bid plans");
@@ -17375,7 +17396,7 @@ var CacheService = class {
17375
17396
  this.cleanupStaleData();
17376
17397
  this.cacheData.matchedLimitOrders[orderId] = {
17377
17398
  holds: holds.map((hold) => ({ limitOrderId: hold.limitOrderId, payout: hold.payout.toString() })),
17378
- timestamp: Date.now()
17399
+ expiresAt: this.expiresAt(orderId)
17379
17400
  };
17380
17401
  } catch (error) {
17381
17402
  this.logger.error({ err: error }, "Error setting matched limit order");
@@ -17385,7 +17406,7 @@ var CacheService = class {
17385
17406
  getPairClassifications(orderId) {
17386
17407
  try {
17387
17408
  const cache = this.cacheData.pairClassifications[orderId];
17388
- if (cache && this.isCacheValid(cache.timestamp, orderId)) {
17409
+ if (cache && this.isCacheValid(cache.expiresAt, orderId)) {
17389
17410
  return cache.pairs;
17390
17411
  }
17391
17412
  return null;
@@ -17398,7 +17419,7 @@ var CacheService = class {
17398
17419
  try {
17399
17420
  this.cacheData.pairClassifications[orderId] = {
17400
17421
  pairs,
17401
- timestamp: Date.now()
17422
+ expiresAt: this.expiresAt(orderId)
17402
17423
  };
17403
17424
  } catch (error) {
17404
17425
  this.logger.error({ err: error }, "Error setting pair classifications");
@@ -17408,7 +17429,7 @@ var CacheService = class {
17408
17429
  getFundingPrepends(orderId) {
17409
17430
  try {
17410
17431
  const cache = this.cacheData.fundingPrepends[orderId];
17411
- if (cache && this.isCacheValid(cache.timestamp, orderId)) {
17432
+ if (cache && this.isCacheValid(cache.expiresAt, orderId)) {
17412
17433
  return {
17413
17434
  calls: cache.calls.map((c) => ({
17414
17435
  target: c.target,
@@ -17432,7 +17453,7 @@ var CacheService = class {
17432
17453
  value: c.value.toString(),
17433
17454
  data: c.data
17434
17455
  })),
17435
- timestamp: Date.now()
17456
+ expiresAt: this.expiresAt(orderId)
17436
17457
  };
17437
17458
  } catch (error) {
17438
17459
  this.logger.error({ err: error }, "Error setting funding prepends");
@@ -17451,10 +17472,10 @@ var CacheService = class {
17451
17472
  */
17452
17473
  isPartialFill(orderId) {
17453
17474
  const cache = this.cacheData.partialFills[orderId];
17454
- return cache !== void 0 && this.isCacheValid(cache.timestamp, orderId) && cache.partial;
17475
+ return cache !== void 0 && this.isCacheValid(cache.expiresAt, orderId) && cache.partial;
17455
17476
  }
17456
17477
  setPartialFill(orderId, partial) {
17457
- this.cacheData.partialFills[orderId] = { partial, timestamp: Date.now() };
17478
+ this.cacheData.partialFills[orderId] = { partial, expiresAt: this.expiresAt(orderId) };
17458
17479
  }
17459
17480
  clearPartialFill(orderId) {
17460
17481
  delete this.cacheData.partialFills[orderId];
@@ -17469,10 +17490,10 @@ var CacheService = class {
17469
17490
  */
17470
17491
  isFeeCheckWaived(orderId) {
17471
17492
  const cache = this.cacheData.feeChecksWaived[orderId];
17472
- return cache !== void 0 && this.isCacheValid(cache.timestamp, orderId) && cache.waived;
17493
+ return cache !== void 0 && this.isCacheValid(cache.expiresAt, orderId) && cache.waived;
17473
17494
  }
17474
17495
  setFeeCheckWaived(orderId, waived) {
17475
- this.cacheData.feeChecksWaived[orderId] = { waived, timestamp: Date.now() };
17496
+ this.cacheData.feeChecksWaived[orderId] = { waived, expiresAt: this.expiresAt(orderId) };
17476
17497
  }
17477
17498
  clearFeeCheckWaived(orderId) {
17478
17499
  delete this.cacheData.feeChecksWaived[orderId];
@@ -23953,6 +23974,10 @@ var IntentFiller = class {
23953
23974
  this.monitor.emit("orderSkipped", { orderId: order.id, reason: "Placement block unknown" });
23954
23975
  return;
23955
23976
  }
23977
+ const releaseWait = order.id && requiredConfirmations > 0 ? this.contractService.cacheService.extendForConfirmations(
23978
+ order.id,
23979
+ await this.confirmationWaitMs(order.source, requiredConfirmations)
23980
+ ) : void 0;
23956
23981
  const abortController = new AbortController();
23957
23982
  const confirmStartMs = Date.now();
23958
23983
  const confirmationPollMs = sourceQuorumClient.size > 1 ? 1e3 : 300;
@@ -24016,7 +24041,7 @@ var IntentFiller = class {
24016
24041
  if (!result) abortController.abort();
24017
24042
  return result;
24018
24043
  })
24019
- ]);
24044
+ ]).finally(() => releaseWait?.());
24020
24045
  const confirmDurationSec = (Date.now() - confirmStartMs) / 1e3;
24021
24046
  this.monitor.emit("orderTiming", {
24022
24047
  orderId: order.id,
@@ -24045,7 +24070,8 @@ var IntentFiller = class {
24045
24070
  evaluationResult.strategy,
24046
24071
  solverSelectionActive,
24047
24072
  inputUsdValue,
24048
- evaluationResult.profitability
24073
+ evaluationResult.profitability,
24074
+ () => this.evaluateOrder(order, canFillCache)
24049
24075
  );
24050
24076
  } catch (error) {
24051
24077
  this.logger.error({ orderId: order.id, err: error }, "Error processing order");
@@ -24126,6 +24152,19 @@ var IntentFiller = class {
24126
24152
  );
24127
24153
  return validStrategies[0];
24128
24154
  }
24155
+ /**
24156
+ * How long `confirmations` take on `chain`, at the block time measured when simplex started.
24157
+ * Zero when there is no block time to be had: the order then keeps the cache's own lifetime,
24158
+ * and an evaluation that expires before its bids is redone.
24159
+ */
24160
+ async confirmationWaitMs(chain, confirmations) {
24161
+ try {
24162
+ return Math.ceil(confirmations * await this.contractService.blockTimeSeconds(chain) * 1e3);
24163
+ } catch (err) {
24164
+ this.logger.warn({ chain, err }, "Could not read the block time to size the order's cache lifetime");
24165
+ return 0;
24166
+ }
24167
+ }
24129
24168
  /**
24130
24169
  * The destination chain's latest block number, the clock `order.deadline` is read on.
24131
24170
  *
@@ -24165,7 +24204,7 @@ var IntentFiller = class {
24165
24204
  if (!order.id) return false;
24166
24205
  return this.contractService.cacheService.isFeeCheckWaived(order.id);
24167
24206
  }
24168
- executeOrder(order, bestStrategy, solverSelectionActive, inputUsdValue, profitUsd) {
24207
+ executeOrder(order, bestStrategy, solverSelectionActive, inputUsdValue, profitUsd, reevaluate) {
24169
24208
  const chainQueue = this.chainQueues.get(getChainId3(order.destination));
24170
24209
  if (!chainQueue) {
24171
24210
  this.logger.error({ chain: order.destination }, "No queue configured for chain");
@@ -24176,12 +24215,19 @@ var IntentFiller = class {
24176
24215
  chainQueue.add(async () => {
24177
24216
  const queueDurationSec = (Date.now() - queuedAtMs) / 1e3;
24178
24217
  this.monitor.emit("orderTiming", { orderId: order.id, phase: "queue_wait", durationSec: queueDurationSec });
24218
+ const cache = this.contractService.cacheService;
24219
+ unpin = order.id ? cache.pinOrder(order.id) : void 0;
24220
+ if (order.id && reevaluate && !cache.getGasEstimate(order.id)) {
24221
+ this.logger.info({ orderId: order.id }, "Order evaluation expired before bidding, evaluating it again");
24222
+ const evaluation = await reevaluate();
24223
+ if (!evaluation) return;
24224
+ bestStrategy = evaluation.strategy;
24225
+ profitUsd = evaluation.profitability;
24226
+ }
24179
24227
  this.logger.info(
24180
24228
  { orderId: order.id, strategy: bestStrategy.name, chain: order.destination },
24181
24229
  "Executing order"
24182
24230
  );
24183
- const cache = this.contractService.cacheService;
24184
- unpin = order.id ? cache.pinOrder(order.id) : void 0;
24185
24231
  const plans = this.limitOrders && order.id ? cache.getBidPlans(order.id) : [];
24186
24232
  let lastResult;
24187
24233
  for (const plan of plans.length > 0 ? plans : [void 0]) {