dexbot 1.4.4 → 1.4.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.
Files changed (56) hide show
  1. package/dist/modules/bots_file_lock.d.ts +4 -4
  2. package/dist/modules/bots_file_lock.d.ts.map +1 -1
  3. package/dist/modules/bots_file_lock.js +16 -53
  4. package/dist/modules/bots_file_lock.js.map +1 -1
  5. package/dist/modules/dexbot_class.d.ts +10 -10
  6. package/dist/modules/dexbot_class.d.ts.map +1 -1
  7. package/dist/modules/dexbot_class.js +18 -8
  8. package/dist/modules/dexbot_class.js.map +1 -1
  9. package/dist/modules/dexbot_cow_runtime.d.ts.map +1 -1
  10. package/dist/modules/dexbot_cow_runtime.js +4 -5
  11. package/dist/modules/dexbot_cow_runtime.js.map +1 -1
  12. package/dist/modules/dexbot_maintenance_runtime.d.ts +2 -2
  13. package/dist/modules/dexbot_maintenance_runtime.d.ts.map +1 -1
  14. package/dist/modules/dexbot_maintenance_runtime.js +8 -7
  15. package/dist/modules/dexbot_maintenance_runtime.js.map +1 -1
  16. package/dist/modules/dexbot_startup_runtime.d.ts.map +1 -1
  17. package/dist/modules/dexbot_startup_runtime.js +1 -0
  18. package/dist/modules/dexbot_startup_runtime.js.map +1 -1
  19. package/dist/modules/dexbot_state_recovery.js +2 -2
  20. package/dist/modules/dexbot_state_recovery.js.map +1 -1
  21. package/dist/modules/order/async_lock.d.ts +12 -3
  22. package/dist/modules/order/async_lock.d.ts.map +1 -1
  23. package/dist/modules/order/async_lock.js +46 -8
  24. package/dist/modules/order/async_lock.js.map +1 -1
  25. package/dist/modules/order/grid.d.ts +10 -10
  26. package/dist/modules/order/grid.d.ts.map +1 -1
  27. package/dist/modules/order/grid.js +75 -92
  28. package/dist/modules/order/grid.js.map +1 -1
  29. package/dist/modules/order/grid_reconcile.d.ts +4 -2
  30. package/dist/modules/order/grid_reconcile.d.ts.map +1 -1
  31. package/dist/modules/order/grid_reconcile.js +70 -55
  32. package/dist/modules/order/grid_reconcile.js.map +1 -1
  33. package/dist/modules/order/grid_reconcile_internal.d.ts +6 -2
  34. package/dist/modules/order/grid_reconcile_internal.d.ts.map +1 -1
  35. package/dist/modules/order/grid_reconcile_internal.js +101 -44
  36. package/dist/modules/order/grid_reconcile_internal.js.map +1 -1
  37. package/dist/modules/order/manager.d.ts +21 -5
  38. package/dist/modules/order/manager.d.ts.map +1 -1
  39. package/dist/modules/order/manager.js +123 -44
  40. package/dist/modules/order/manager.js.map +1 -1
  41. package/dist/modules/order/strategy.d.ts.map +1 -1
  42. package/dist/modules/order/strategy.js +9 -2
  43. package/dist/modules/order/strategy.js.map +1 -1
  44. package/dist/modules/order/sync_engine.d.ts +7 -3
  45. package/dist/modules/order/sync_engine.d.ts.map +1 -1
  46. package/dist/modules/order/sync_engine.js +10 -23
  47. package/dist/modules/order/sync_engine.js.map +1 -1
  48. package/dist/modules/order/utils/order.d.ts +5 -2
  49. package/dist/modules/order/utils/order.d.ts.map +1 -1
  50. package/dist/modules/order/utils/order.js +23 -6
  51. package/dist/modules/order/utils/order.js.map +1 -1
  52. package/dist/modules/order/utils/system.d.ts +2 -1
  53. package/dist/modules/order/utils/system.d.ts.map +1 -1
  54. package/dist/modules/order/utils/system.js +8 -5
  55. package/dist/modules/order/utils/system.js.map +1 -1
  56. package/package.json +1 -1
@@ -68,9 +68,11 @@
68
68
  *
69
69
  * Re-entrancy detection uses AsyncLocalStorage (Node.js) to distinguish
70
70
  * truly nested calls (same async context) from separate concurrent
71
- * callers. If AsyncLocalStorage is unavailable in the current runtime
72
- * (e.g. a browser bundle shim), the lock falls back to a simpler
73
- * _holding flag that treats any concurrent call as re-entrant.
71
+ * callers. The store tracks a Set of all lock IDs held in the current
72
+ * async context chain, preserving outer lock identity across nested
73
+ * acquisitions. If AsyncLocalStorage is unavailable in the current
74
+ * runtime (e.g. a browser bundle shim), the lock falls back to a
75
+ * simpler _holding flag that treats any concurrent call as re-entrant.
74
76
  *
75
77
  * CRITICAL INVARIANTS:
76
78
  * - _locked = true ONLY if callback is currently executing
@@ -106,6 +108,7 @@ class AsyncLock {
106
108
  _defaultTimeout;
107
109
  _onContention;
108
110
  _lockId;
111
+ _orphaned;
109
112
  constructor(options = {}) {
110
113
  this._queue = [];
111
114
  this._locked = false;
@@ -114,6 +117,7 @@ class AsyncLock {
114
117
  this._defaultTimeout = options.timeout || null;
115
118
  this._onContention = options.onContention || null;
116
119
  this._lockId = Symbol('AsyncLock');
120
+ this._orphaned = false;
117
121
  }
118
122
  /**
119
123
  * Acquire the lock and execute callback exclusively
@@ -128,14 +132,19 @@ class AsyncLock {
128
132
  // context, run the callback directly. Uses AsyncLocalStorage (Node.js)
129
133
  // to distinguish truly nested calls from separate concurrent callers.
130
134
  // Falls back to _holding flag in environments without AsyncLocalStorage.
131
- const contextId = _lockCtx ? _lockCtx.getStore() : undefined;
132
- if (contextId === this._lockId || (!_lockCtx && this._holding)) {
135
+ const contextSet = _lockCtx ? _lockCtx.getStore() : undefined;
136
+ if ((contextSet && contextSet.has(this._lockId)) || (!_lockCtx && this._holding)) {
133
137
  return callback();
134
138
  }
135
139
  const timeout = options.timeout || this._defaultTimeout;
136
140
  const cancelToken = options.cancelToken;
137
141
  const wrappedCallback = _lockCtx
138
- ? () => _lockCtx.run(this._lockId, callback)
142
+ ? () => {
143
+ const prevSet = _lockCtx.getStore() || new Set();
144
+ const newSet = new Set(prevSet);
145
+ newSet.add(this._lockId);
146
+ return _lockCtx.run(newSet, callback);
147
+ }
139
148
  : callback;
140
149
  return new Promise((resolve, reject) => {
141
150
  let timer;
@@ -223,6 +232,17 @@ class AsyncLock {
223
232
  this._locked = false;
224
233
  this._processQueue();
225
234
  }
235
+ else if (this._orphaned) {
236
+ // Stale callback finishing after forceRelease. The
237
+ // forceRelease deferred _locked = false to us via the
238
+ // _orphaned flag. Release the lock so queued callbacks
239
+ // can proceed. This prevents concurrent execution: the
240
+ // stale callback continues to hold _locked until it
241
+ // finishes, blocking any new acquirer.
242
+ this._orphaned = false;
243
+ this._locked = false;
244
+ this._processQueue();
245
+ }
226
246
  // After a callback completes, if there are still queued items
227
247
  // (but the previous _locked=false path already called
228
248
  // _processQueue which started the next one), check whether
@@ -247,7 +267,8 @@ class AsyncLock {
247
267
  */
248
268
  isReentrant() {
249
269
  if (_lockCtx) {
250
- return _lockCtx.getStore() === this._lockId;
270
+ const store = _lockCtx.getStore();
271
+ return store ? store.has(this._lockId) : false;
251
272
  }
252
273
  return this._holding;
253
274
  }
@@ -288,6 +309,12 @@ class AsyncLock {
288
309
  * stale callback from interfering with a new acquirer that claimed
289
310
  * the lock after forceRelease.
290
311
  *
312
+ * CONCURRENT EXECUTION GUARD: If a callback is currently executing
313
+ * (_holding is true), forceRelease defers _locked = false to the
314
+ * stale callback's finally block via the _orphaned flag. This
315
+ * prevents a new acquirer from entering while the stale callback
316
+ * is still running, preserving mutual exclusion.
317
+ *
291
318
  * @returns {number} Count of cleared items
292
319
  */
293
320
  forceRelease() {
@@ -296,6 +323,7 @@ class AsyncLock {
296
323
  // finally block — it will see generation mismatch and skip
297
324
  // touching _locked / _processQueue.
298
325
  this._generation++;
326
+ const wasHolding = this._holding;
299
327
  this._holding = false;
300
328
  while (this._queue.length > 0) {
301
329
  const { reject, timer } = this._queue.shift();
@@ -303,7 +331,17 @@ class AsyncLock {
303
331
  clearTimeout(timer);
304
332
  reject(new Error('Lock force-released'));
305
333
  }
306
- this._locked = false;
334
+ if (wasHolding) {
335
+ // A callback is currently executing — defer lock release to
336
+ // the stale callback's finally block, which detects the
337
+ // orphan state via generation mismatch + _orphaned flag and
338
+ // releases _locked when done. This prevents concurrent
339
+ // execution between the stale callback and a new acquirer.
340
+ this._orphaned = true;
341
+ }
342
+ else {
343
+ this._locked = false;
344
+ }
307
345
  return count;
308
346
  }
309
347
  }
@@ -1 +1 @@
1
- {"version":3,"file":"async_lock.js","sourceRoot":"","sources":["../../../modules/order/async_lock.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"async_lock.js","sourceRoot":"","sources":["../../../modules/order/async_lock.ts"],"names":[],"mappings":"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"}
@@ -65,9 +65,8 @@
65
65
  * 21. getDustOrders(manager, partials, side) - Get all dust order IDs (public)
66
66
  * 22. determineOrderSideByFunds(manager, currentMarketPrice) - Determine priority side
67
67
  *
68
- * SPREAD CORRECTION (2 methods)
69
- * 23. calculateGeometricSizeForSpreadCorrection(manager, targetType) - Calculate correction size
70
- * 24. prepareSpreadCorrectionOrders(manager, preferredSide) - Prepare correction orders
68
+ * SPREAD CORRECTION (1 method)
69
+ * 23. prepareSpreadCorrectionOrders(manager, preferredSide) - Prepare correction orders
71
70
  *
72
71
  * DUST DETECTION (1 method - internal)
73
72
  * 25. _getDustOrders(manager, partials, type) - Internal dust detection helper
@@ -193,6 +192,14 @@ export declare function _getSizingContext(manager: any, side: any, { skipRecalc
193
192
  export declare function createOrderGrid(config: any): any;
194
193
  /**
195
194
  * Restore a persisted grid snapshot onto a manager instance.
195
+ *
196
+ * Side effects on manager:
197
+ * - Reassigns all slot types to match current boundary + gapSlots
198
+ * (fixes stale persisted types that cause ILLEGAL_SPREAD_STATE)
199
+ * - Sets `manager._gapSlots` to the computed gapSlots so strategy reads
200
+ * the creation-time value instead of recomputing from live config
201
+ * - Sanitizes phantom orders (ACTIVE/PARTIAL without orderId → VIRTUAL)
202
+ *
196
203
  * @param {import('./types').OrderManager} manager - The manager instance.
197
204
  * @param {Array<import('./types').GridOrderSlot>} grid - The persisted grid array.
198
205
  * @param {number|null} [boundaryIdx=null] - The master boundary index.
@@ -431,13 +438,6 @@ export declare function getDustOrders(manager: any, partials: any, side: any): P
431
438
  * @returns {{ side: import('./types').OrderType|null, reason: string }} The side to correct on, or null if insufficient funds.
432
439
  */
433
440
  export declare function determineOrderSideByFunds(manager: any, currentMarketPrice: any): any;
434
- /**
435
- * Calculate the geometric ideal size for a new order being placed during spread correction.
436
- * @param {import('./types').OrderManager} manager - The manager instance.
437
- * @param {import('./types').OrderType} targetType - The type of order being placed (ORDER_TYPES.BUY or ORDER_TYPES.SELL).
438
- * @returns {Promise<number|null>} The calculated geometric size.
439
- */
440
- export declare function calculateGeometricSizeForSpreadCorrection(manager: any, targetType: any): Promise<any>;
441
441
  /**
442
442
  * Prepares one or more orders to correct a wide spread.
443
443
  * @param {import('./types').OrderManager} manager - The OrderManager instance.
@@ -1 +1 @@
1
- {"version":3,"file":"grid.d.ts","sourceRoot":"","sources":["../../../modules/order/grid.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"grid.d.ts","sourceRoot":"","sources":["../../../modules/order/grid.ts"],"names":[],"mappings":"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"}
@@ -66,9 +66,8 @@
66
66
  * 21. getDustOrders(manager, partials, side) - Get all dust order IDs (public)
67
67
  * 22. determineOrderSideByFunds(manager, currentMarketPrice) - Determine priority side
68
68
  *
69
- * SPREAD CORRECTION (2 methods)
70
- * 23. calculateGeometricSizeForSpreadCorrection(manager, targetType) - Calculate correction size
71
- * 24. prepareSpreadCorrectionOrders(manager, preferredSide) - Prepare correction orders
69
+ * SPREAD CORRECTION (1 method)
70
+ * 23. prepareSpreadCorrectionOrders(manager, preferredSide) - Prepare correction orders
72
71
  *
73
72
  * DUST DETECTION (1 method - internal)
74
73
  * 25. _getDustOrders(manager, partials, type) - Internal dust detection helper
@@ -151,7 +150,6 @@ exports.checkWindowDust = checkWindowDust;
151
150
  exports.hasAnyDust = hasAnyDust;
152
151
  exports.getDustOrders = getDustOrders;
153
152
  exports.determineOrderSideByFunds = determineOrderSideByFunds;
154
- exports.calculateGeometricSizeForSpreadCorrection = calculateGeometricSizeForSpreadCorrection;
155
153
  exports.prepareSpreadCorrectionOrders = prepareSpreadCorrectionOrders;
156
154
  const constants_1 = require("../constants");
157
155
  const { GRID_COMPARISON } = constants_1.GRID_LIMITS;
@@ -461,7 +459,7 @@ function createOrderGrid(config) {
461
459
  buy: Math.floor(gapSlots / 2),
462
460
  sell: gapSlots - Math.floor(gapSlots / 2)
463
461
  };
464
- return { orders: updatedOrders, boundaryIdx, initialSpreadCount };
462
+ return { orders: updatedOrders, boundaryIdx, initialSpreadCount, gapSlots };
465
463
  }
466
464
  /**
467
465
  * Internal utility to clear all order-related manager caches.
@@ -480,6 +478,14 @@ function _clearOrderCachesLogic(manager) {
480
478
  }
481
479
  /**
482
480
  * Restore a persisted grid snapshot onto a manager instance.
481
+ *
482
+ * Side effects on manager:
483
+ * - Reassigns all slot types to match current boundary + gapSlots
484
+ * (fixes stale persisted types that cause ILLEGAL_SPREAD_STATE)
485
+ * - Sets `manager._gapSlots` to the computed gapSlots so strategy reads
486
+ * the creation-time value instead of recomputing from live config
487
+ * - Sanitizes phantom orders (ACTIVE/PARTIAL without orderId → VIRTUAL)
488
+ *
483
489
  * @param {import('./types').OrderManager} manager - The manager instance.
484
490
  * @param {Array<import('./types').GridOrderSlot>} grid - The persisted grid array.
485
491
  * @param {number|null} [boundaryIdx=null] - The master boundary index.
@@ -505,31 +511,32 @@ async function loadGrid(manager, grid, boundaryIdx = null) {
505
511
  manager._restoreBoundary(boundaryIdx);
506
512
  manager.logger?.log?.(`Restored boundary index: ${boundaryIdx}`, 'info');
507
513
  }
508
- // Reassign slot types for virtual slots based on current boundary.
509
- // Over time, boundary shifts leave stale SPREAD/BUY/SELL types on
510
- // virtual slots that no longer match their position. Virtual slots
511
- // have no on-chain commitment, so their type is safely corrected.
514
+ // Reassign slot types based on current boundary.
515
+ // Every slot's type must match its position in the price-sorted rail
516
+ // relative to the boundary + gapSlots. Stale persisted types cause
517
+ // split spread zones and ILLEGAL_SPREAD_STATE errors. The subsequent
518
+ // sync will detect type mismatches with chain orders (e.g. a BUY-zone
519
+ // slot holding a SELL chain order) and auto-cancel + recreate them.
512
520
  if (typeof boundaryIdx === 'number') {
513
521
  const gapSlots = calculateGapSlots(manager.config?.incrementPercent, manager.config?.targetSpreadPercent, manager.config?.gridLimits);
522
+ manager._gapSlots = gapSlots;
514
523
  const buyEndIdx = boundaryIdx;
515
524
  const sellStartIdx = (0, math_1.getSellStartIdx)(boundaryIdx, gapSlots);
516
525
  let reassignCount = 0;
517
526
  grid = grid.map((slot, i) => {
518
- if (slot.state === constants_1.ORDER_STATES.VIRTUAL && !slot.orderId) {
519
- const correctType = (i <= buyEndIdx)
520
- ? constants_1.ORDER_TYPES.BUY
521
- : (i >= sellStartIdx)
522
- ? constants_1.ORDER_TYPES.SELL
523
- : constants_1.ORDER_TYPES.SPREAD;
524
- if (slot.type !== correctType) {
525
- reassignCount++;
526
- return { ...slot, type: correctType };
527
- }
527
+ const correctType = (i <= buyEndIdx)
528
+ ? constants_1.ORDER_TYPES.BUY
529
+ : (i >= sellStartIdx)
530
+ ? constants_1.ORDER_TYPES.SELL
531
+ : constants_1.ORDER_TYPES.SPREAD;
532
+ if (slot.type !== correctType) {
533
+ reassignCount++;
534
+ return { ...slot, type: correctType };
528
535
  }
529
536
  return slot;
530
537
  });
531
538
  if (reassignCount > 0) {
532
- manager.logger?.log?.(`[GRID-LOAD] Reassigned ${reassignCount} stale virtual slot type(s) based on boundary ${boundaryIdx}`, 'warn');
539
+ manager.logger?.log?.(`[GRID-TYPE-CORRECT] Reassigned ${reassignCount} stale slot type(s) based on boundary ${boundaryIdx}`, 'warn');
533
540
  }
534
541
  }
535
542
  // Gap 6: Grid size cap — validate grid slot count against expected maximum.
@@ -779,12 +786,13 @@ async function initializeGrid(manager) {
779
786
  // Continuing would create grid with 0 fund allocation, rendering it non-functional
780
787
  throw new Error(`Cannot initialize grid without account totals: ${(0, errors_1.getErrorMessage)(e)}`);
781
788
  }
782
- const { orders, boundaryIdx, initialSpreadCount } = createOrderGrid({
789
+ const { orders, boundaryIdx, initialSpreadCount, gapSlots } = createOrderGrid({
783
790
  ...manager.config,
784
791
  startPrice: gridStartPrice,
785
792
  minPrice: resolvedMinP,
786
793
  maxPrice: resolvedMaxP,
787
794
  });
795
+ manager._gapSlots = gapSlots;
788
796
  // RC-8: Update boundary with notification to dependent systems
789
797
  // Persist master boundary for StrategyEngine
790
798
  if (manager.boundaryIdx !== boundaryIdx) {
@@ -1180,7 +1188,7 @@ async function updateGridFromBlockchainSnapshot(manager, orderType = 'both', fro
1180
1188
  // that a shift is needed. The boundary is only written atomically
1181
1189
  // inside _commitWorkingGrid via _setBoundary.
1182
1190
  if (overrideBoundaryIdx !== null && overrideBoundaryIdx !== manager.boundaryIdx) {
1183
- const gapSlots = calculateGapSlots(manager.config.incrementPercent, manager.config.targetSpreadPercent, manager.config.gridLimits);
1191
+ const gapSlots = manager._gapSlots ?? calculateGapSlots(manager.config.incrementPercent, manager.config.targetSpreadPercent, manager.config.gridLimits);
1184
1192
  const allSlots = Array.from(workingGrid.values())
1185
1193
  .filter((s) => s.price != null)
1186
1194
  .sort((a, b) => a.price - b.price);
@@ -1438,6 +1446,10 @@ async function checkSpreadCondition(manager, _BitShares, updateOrdersOnChainBatc
1438
1446
  // This prevents concurrent fill processing from modifying funds while we're making decisions
1439
1447
  let correction = null;
1440
1448
  let shouldApplyCorrection = false;
1449
+ if (!manager._gridLock) {
1450
+ manager.logger?.log?.('Spread check skipped: no grid lock available', 'warn');
1451
+ return { ordersPlaced: 0, partialsMoved: 0 };
1452
+ }
1441
1453
  // Derive current market price from the bot's own grid (no blockchain call needed).
1442
1454
  // Grid prices are in B/A format (e.g. BTS/XRP) so no inversion is required.
1443
1455
  // Mid between best bid and best ask is the most current price the bot has.
@@ -1447,7 +1459,7 @@ async function checkSpreadCondition(manager, _BitShares, updateOrdersOnChainBatc
1447
1459
  const lastPrice = (bestBuy !== null && bestSell !== null)
1448
1460
  ? (bestBuy + bestSell) / 2
1449
1461
  : Number(manager.config.startPrice) || 0;
1450
- // FIX: Use optional chaining for lock - if no lock exists, execute synchronously
1462
+ // Lock guard is handled at function entry — if _gridLock is absent we return early.
1451
1463
  let fundSnapshot = null;
1452
1464
  // Detect empty-side condition: when one side has zero on-chain orders,
1453
1465
  // the spread is technically infinite and shouldFlagOutOfSpread's old
@@ -1485,7 +1497,7 @@ async function checkSpreadCondition(manager, _BitShares, updateOrdersOnChainBatc
1485
1497
  const allSlots = Array.from(manager.orders.values())
1486
1498
  .filter((o) => o.price != null)
1487
1499
  .sort((a, b) => a.price - b.price);
1488
- const gapSlots = calculateGapSlots(manager.config.incrementPercent, manager.config.targetSpreadPercent, manager.config.gridLimits);
1500
+ const gapSlots = manager._gapSlots ?? calculateGapSlots(manager.config.incrementPercent, manager.config.targetSpreadPercent, manager.config.gridLimits);
1489
1501
  const railLen = allSlots.length;
1490
1502
  const buyEndIdx = manager.boundaryIdx;
1491
1503
  const sellStartIdx = (0, math_1.getSellStartIdx)(manager.boundaryIdx, gapSlots);
@@ -1540,12 +1552,20 @@ async function checkSpreadCondition(manager, _BitShares, updateOrdersOnChainBatc
1540
1552
  shouldApplyCorrection = await manager._gridLock.acquire(executeSpreadCheck);
1541
1553
  }
1542
1554
  catch (err) {
1543
- manager.logger?.log?.(`Error checking spread condition: ${(0, errors_1.getErrorMessage)(err)}`, 'warn');
1555
+ manager.logger?.log?.(`Error checking spread condition: ${(0, errors_1.getErrorMessage)(err)}`, 'error');
1556
+ // Track failure in recovery state for external monitoring.
1557
+ // Do NOT throw — the startup runtime path lacks a try/catch and
1558
+ // a throw would crash startup. The error is symptom of a deeper
1559
+ // issue (lock contention, grid inconsistency) that should be
1560
+ // diagnosed separately.
1561
+ if (manager._recoveryState) {
1562
+ manager._recoveryState = { ...manager._recoveryState, lastFailureAt: Date.now() };
1563
+ }
1544
1564
  return { ordersPlaced: 0, partialsMoved: 0 };
1545
1565
  }
1546
- // FIX: Apply blockchain operations OUTSIDE the lock to reduce lock contention
1547
- // The lock is only needed for fund verification; order placement doesn't need it
1548
- // Pre-flight fund verification to mitigate TOCTOU between lock release and broadcast
1566
+ // Blockchain operations are intentionally OUTSIDE the lock to reduce lock contention.
1567
+ // The lock is only needed for fund verification; order placement doesn't need it.
1568
+ // Pre-flight fund verification mitigates TOCTOU between lock release and broadcast.
1549
1569
  if (shouldApplyCorrection && updateOrdersOnChainBatch && correction && fundSnapshot) {
1550
1570
  const currentFunds = _snapshotFundState(manager);
1551
1571
  const fundChanged = fundSnapshot.buyFree !== currentFunds.buyFree
@@ -1554,28 +1574,27 @@ async function checkSpreadCondition(manager, _BitShares, updateOrdersOnChainBatc
1554
1574
  || fundSnapshot.sellLocked !== currentFunds.sellLocked;
1555
1575
  if (fundChanged) {
1556
1576
  // TOCTOU: fund state changed between lock release and broadcast.
1557
- // Instead of silently aborting, re-plan with fresh funds so the
1558
- // correction still applies on this cycle. The pre-flight check
1559
- // still guards against placing orders based on stale fund snapshots.
1560
- // Re-acquire _gridLock for the re-plan to ensure consistent grid
1561
- // state (the lock is re-entrant for this call chain — the outer
1562
- // acquire's callback completed before we reach here, so there is
1563
- // no nested lock to recurse into). If determineOrderSideByFunds
1564
- // or prepareSpreadCorrectionOrders grow to hold the lock for
1565
- // heavy work, hoist the result to avoid serial re-execution.
1566
- const rePlanResult = await manager._gridLock.acquire(async () => {
1567
- const decision = determineOrderSideByFunds(manager, lastPrice);
1568
- if (!decision.side)
1569
- return { side: false };
1570
- const c = await prepareSpreadCorrectionOrders(manager, decision.side, manager.outOfSpread);
1571
- return { side: true, correction: c };
1572
- });
1573
- if (!rePlanResult.side) {
1577
+ // Lock-free re-plan — no _gridLock needed because the fund read
1578
+ // (recalculateFunds) is serialized by _fundLock internally, and
1579
+ // the remaining logic is read-only against COW-frozen state.
1580
+ // All grid-lock-needing work (fund verification, grid reads) is
1581
+ // done under the single outer acquire above; this re-plan runs
1582
+ // after that lock was released.
1583
+ // Refresh lastPrice from current grid state — the grid may
1584
+ // have changed since function entry (TOCTOU).
1585
+ const freshOnChain = _getOnChainOrders(manager);
1586
+ const freshBest = (0, math_1.getGridBestPrices)(freshOnChain.onChainBuys, freshOnChain.onChainSells);
1587
+ const freshPrice = (freshBest.bestBuy !== null && freshBest.bestSell !== null)
1588
+ ? (freshBest.bestBuy + freshBest.bestSell) / 2
1589
+ : Number(manager.config.startPrice) || 0;
1590
+ const rePlanDecision = determineOrderSideByFunds(manager, freshPrice);
1591
+ if (!rePlanDecision.side) {
1574
1592
  manager.logger?.log?.(`[SPREAD] Fund state changed; no side has sufficient funds for re-plan. Skipping cycle.`, 'warn');
1575
1593
  return { ordersPlaced: 0, partialsMoved: 0 };
1576
1594
  }
1577
- correction = rePlanResult.correction;
1578
- if (correction && ((correction.ordersToPlace?.length || 0) + (correction.ordersToUpdate?.length || 0) > 0)) {
1595
+ const rePlanCorrection = await prepareSpreadCorrectionOrders(manager, rePlanDecision.side, manager.outOfSpread);
1596
+ if (rePlanCorrection && ((rePlanCorrection.ordersToPlace?.length || 0) + (rePlanCorrection.ordersToUpdate?.length || 0) > 0)) {
1597
+ correction = rePlanCorrection;
1579
1598
  fundSnapshot = currentFunds;
1580
1599
  manager.logger?.log?.(`[SPREAD] Fund state changed between lock release and broadcast — ` +
1581
1600
  `re-planned with updated funds: ${correction.ordersToPlace?.length || 0} creates, ` +
@@ -1832,40 +1851,6 @@ function determineOrderSideByFunds(manager, currentMarketPrice) {
1832
1851
  }
1833
1852
  return { side, reason: side ? `Choosing ${side}` : 'Insufficient funds or committed inventory' };
1834
1853
  }
1835
- /**
1836
- * Calculate the geometric ideal size for a new order being placed during spread correction.
1837
- * @param {import('./types').OrderManager} manager - The manager instance.
1838
- * @param {import('./types').OrderType} targetType - The type of order being placed (ORDER_TYPES.BUY or ORDER_TYPES.SELL).
1839
- * @returns {Promise<number|null>} The calculated geometric size.
1840
- */
1841
- async function calculateGeometricSizeForSpreadCorrection(manager, targetType) {
1842
- const side = targetType === constants_1.ORDER_TYPES.BUY ? 'buy' : 'sell';
1843
- // Count only on-chain orders (ACTIVE+PARTIAL) to avoid diluting the
1844
- // spread-correction order size across hundreds of virtual slots on a
1845
- // full-rail grid. Virtual slots have their capital tracked separately
1846
- // in funds.virtual and should not compete for the free budget.
1847
- const slotsCount = Array.from(manager.orders.values())
1848
- .filter((o) => o.type === targetType && (o.state === constants_1.ORDER_STATES.ACTIVE || o.state === constants_1.ORDER_STATES.PARTIAL))
1849
- .length + 1;
1850
- // Use centralized sizing context (respects botFunds % allocation)
1851
- const ctx = await _getSizingContext(manager, side);
1852
- if (!ctx || ctx.budget <= 0 || slotsCount < 1)
1853
- return null;
1854
- // ALLOW slotsCount === 1 to enable spread correction even if a side is completely missing
1855
- const dummy = Array.from({ length: slotsCount }, () => ({ type: targetType }));
1856
- try {
1857
- const sized = (0, math_1.calculateOrderSizes)(dummy, manager.config, side === 'sell' ? ctx.budget : 0, side === 'buy' ? ctx.budget : 0, 0, 0, ctx.precision, ctx.precision);
1858
- if (!Array.isArray(sized) || sized.length === 0) {
1859
- manager.logger?.log?.(`calculateOrderSizes returned invalid result for spread correction`, 'warn');
1860
- return null;
1861
- }
1862
- return side === 'sell' ? sized[0].size : sized[sized.length - 1].size;
1863
- }
1864
- catch (e) {
1865
- manager.logger?.log?.(`Error calculating geometric size for spread correction: ${(0, errors_1.getErrorMessage)(e)}`, 'warn');
1866
- return null;
1867
- }
1868
- }
1869
1854
  /**
1870
1855
  * Prepares one or more orders to correct a wide spread.
1871
1856
  * @param {import('./types').OrderManager} manager - The OrderManager instance.
@@ -1904,17 +1889,15 @@ async function prepareSpreadCorrectionOrders(manager, preferredSide, outOfSpread
1904
1889
  .filter((o) => o.price != null && Number.isFinite(o.price))
1905
1890
  .sort((a, b) => a.price - b.price);
1906
1891
  const slotIndexMap = new Map(allSlotsByPrice.map((o, i) => [o.id, i]));
1907
- const gapSlots = calculateGapSlots(manager.config?.incrementPercent, manager.config?.targetSpreadPercent, manager.config?.gridLimits);
1908
- // Compute boundary from current fund state for local slot classification.
1909
- // syncBoundaryToFunds is a pure computation — it does NOT mutate
1910
- // manager.boundaryIdx. The boundary is only updated atomically through
1911
- // _commitWorkingGrid in the COW pipeline via _setBoundary.
1912
- const boundarySync = (0, system_1.syncBoundaryToFunds)(manager);
1913
- const bIdx = (boundarySync.changed && boundarySync.newIdx !== undefined)
1914
- ? boundarySync.newIdx
1915
- : (manager.boundaryIdx ?? 0);
1916
- const buyEndIdx = bIdx;
1917
- const sellStartIdx = (0, math_1.getSellStartIdx)(bIdx, gapSlots);
1892
+ const gapSlots = manager._gapSlots ?? calculateGapSlots(manager.config?.incrementPercent, manager.config?.targetSpreadPercent, manager.config?.gridLimits);
1893
+ // Use the committed boundary for slot classification — never a speculative
1894
+ // value from syncBoundaryToFunds that hasn't been persisted through the COW
1895
+ // pipeline. If the boundary shifts later via _commitWorkingGrid, the next
1896
+ // spread correction cycle will re-classify with the updated committed value.
1897
+ // This prevents TOCTOU-style inconsistency where slot types are chosen
1898
+ // against a boundary that was never atomically committed to manager.orders.
1899
+ const buyEndIdx = manager.boundaryIdx ?? 0;
1900
+ const sellStartIdx = (0, math_1.getSellStartIdx)(manager.boundaryIdx, gapSlots);
1918
1901
  const getSlotCorrectType = (slot) => {
1919
1902
  const idx = slotIndexMap.get(slot.id);
1920
1903
  if (idx === undefined)