dexbot 1.2.0 → 1.2.2
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/credential-daemon.d.ts.map +1 -1
- package/dist/credential-daemon.js +6 -3
- package/dist/credential-daemon.js.map +1 -1
- package/dist/modules/bitshares-native/lru_cache.d.ts +9 -0
- package/dist/modules/bitshares-native/lru_cache.d.ts.map +1 -1
- package/dist/modules/bitshares-native/lru_cache.js +12 -0
- package/dist/modules/bitshares-native/lru_cache.js.map +1 -1
- package/dist/modules/bitshares-native/tx/builder.d.ts +4 -0
- package/dist/modules/bitshares-native/tx/builder.d.ts.map +1 -1
- package/dist/modules/bitshares-native/tx/builder.js +19 -0
- package/dist/modules/bitshares-native/tx/builder.js.map +1 -1
- package/dist/modules/bitshares-native/tx/tx_cache.d.ts +7 -0
- package/dist/modules/bitshares-native/tx/tx_cache.d.ts.map +1 -1
- package/dist/modules/bitshares-native/tx/tx_cache.js +11 -0
- package/dist/modules/bitshares-native/tx/tx_cache.js.map +1 -1
- package/dist/modules/bitshares_client.d.ts.map +1 -1
- package/dist/modules/bitshares_client.js +5 -0
- package/dist/modules/bitshares_client.js.map +1 -1
- package/dist/modules/constants.d.ts +1 -0
- package/dist/modules/constants.d.ts.map +1 -1
- package/dist/modules/constants.js +1 -0
- package/dist/modules/constants.js.map +1 -1
- package/dist/modules/credential_policy.d.ts.map +1 -1
- package/dist/modules/credential_policy.js +7 -5
- package/dist/modules/credential_policy.js.map +1 -1
- package/dist/modules/dexbot_class.d.ts +0 -1
- package/dist/modules/dexbot_class.d.ts.map +1 -1
- package/dist/modules/dexbot_class.js +119 -57
- package/dist/modules/dexbot_class.js.map +1 -1
- package/dist/modules/dexbot_fill_runtime.d.ts.map +1 -1
- package/dist/modules/dexbot_fill_runtime.js +3 -0
- package/dist/modules/dexbot_fill_runtime.js.map +1 -1
- package/dist/modules/dexbot_maintenance_runtime.d.ts.map +1 -1
- package/dist/modules/dexbot_maintenance_runtime.js +4 -0
- package/dist/modules/dexbot_maintenance_runtime.js.map +1 -1
- package/dist/modules/node_manager.d.ts +1 -0
- package/dist/modules/node_manager.d.ts.map +1 -1
- package/dist/modules/node_manager.js +11 -1
- package/dist/modules/node_manager.js.map +1 -1
- package/dist/modules/order/accounting.d.ts +8 -2
- package/dist/modules/order/accounting.d.ts.map +1 -1
- package/dist/modules/order/accounting.js +29 -16
- package/dist/modules/order/accounting.js.map +1 -1
- package/dist/modules/order/grid.js +1 -1
- package/dist/modules/order/grid.js.map +1 -1
- package/dist/modules/order/grid_reconcile_internal.js +13 -2
- package/dist/modules/order/grid_reconcile_internal.js.map +1 -1
- package/dist/modules/order/index.d.ts +3 -8
- package/dist/modules/order/index.d.ts.map +1 -1
- package/dist/modules/order/index.js +3 -10
- package/dist/modules/order/index.js.map +1 -1
- package/dist/modules/order/manager.d.ts +84 -16
- package/dist/modules/order/manager.d.ts.map +1 -1
- package/dist/modules/order/manager.js +131 -235
- package/dist/modules/order/manager.js.map +1 -1
- package/dist/modules/order/strategy.js +1 -1
- package/dist/modules/order/strategy.js.map +1 -1
- package/dist/modules/order/sync_engine.d.ts +2 -3
- package/dist/modules/order/sync_engine.d.ts.map +1 -1
- package/dist/modules/order/sync_engine.js +53 -20
- package/dist/modules/order/sync_engine.js.map +1 -1
- package/dist/modules/order/utils/math.d.ts +28 -1
- package/dist/modules/order/utils/math.d.ts.map +1 -1
- package/dist/modules/order/utils/math.js +40 -2
- package/dist/modules/order/utils/math.js.map +1 -1
- package/dist/modules/order/utils/order.d.ts.map +1 -1
- package/dist/modules/order/utils/order.js +42 -6
- package/dist/modules/order/utils/order.js.map +1 -1
- package/dist/modules/types.d.ts +7 -12
- package/dist/modules/types.d.ts.map +1 -1
- package/dist/modules/utils/math_utils.d.ts +3 -6
- package/dist/modules/utils/math_utils.d.ts.map +1 -1
- package/dist/modules/utils/math_utils.js +1 -14
- package/dist/modules/utils/math_utils.js.map +1 -1
- package/dist/{modules/order → scripts}/runner.d.ts +15 -9
- package/dist/scripts/runner.d.ts.map +1 -0
- package/dist/{modules/order → scripts}/runner.js +24 -45
- package/dist/scripts/runner.js.map +1 -0
- package/package.json +1 -2
- package/scripts/README.md +13 -0
- package/dist/modules/cli_whitelist_args.d.ts +0 -6
- package/dist/modules/cli_whitelist_args.d.ts.map +0 -1
- package/dist/modules/cli_whitelist_args.js +0 -13
- package/dist/modules/cli_whitelist_args.js.map +0 -1
- package/dist/modules/order/runner.d.ts.map +0 -1
- package/dist/modules/order/runner.js.map +0 -1
|
@@ -134,7 +134,6 @@ class DEXBot {
|
|
|
134
134
|
_currentCycleId;
|
|
135
135
|
_autoCancelOrphanCycleMarker;
|
|
136
136
|
_autoCancelOrphanSubCount;
|
|
137
|
-
_orphanFillsCreditedAt;
|
|
138
137
|
_consecutiveConsumeFailures;
|
|
139
138
|
_consumeFailureFirstAt;
|
|
140
139
|
_reconnectUnregister;
|
|
@@ -226,7 +225,6 @@ class DEXBot {
|
|
|
226
225
|
this._currentCycleId = 0;
|
|
227
226
|
this._autoCancelOrphanCycleMarker = null;
|
|
228
227
|
this._autoCancelOrphanSubCount = 0;
|
|
229
|
-
this._orphanFillsCreditedAt = null;
|
|
230
228
|
// Per-session guard: ghost order IDs successfully cancelled
|
|
231
229
|
// (avoids spamming the chain with repeated cancel attempts for the same
|
|
232
230
|
// orphan residual on every fill cycle).
|
|
@@ -349,7 +347,7 @@ class DEXBot {
|
|
|
349
347
|
shadowLocks: this.manager?.shadowOrderIds?.size || 0,
|
|
350
348
|
batchInFlight: this._batchInFlight,
|
|
351
349
|
recoveryInFlight: this._recoverySyncInFlight,
|
|
352
|
-
broadcasting: this.manager?.
|
|
350
|
+
broadcasting: this.manager?.isBroadcastingActive?.() || false
|
|
353
351
|
};
|
|
354
352
|
}
|
|
355
353
|
/**
|
|
@@ -1070,24 +1068,30 @@ class DEXBot {
|
|
|
1070
1068
|
if (trackedFillKey && !this._isNewFillKey(trackedFillKey, processedFillKeys, '[POST-RESET]', fillOp.order_id)) {
|
|
1071
1069
|
continue;
|
|
1072
1070
|
}
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1071
|
+
this.manager.lockOrders([gridOrder.id]);
|
|
1072
|
+
try {
|
|
1073
|
+
const accountingResult = await this._applyReplaySafeTrackedFillAccounting(fill, fillOp, {
|
|
1074
|
+
context: 'POST-RESET',
|
|
1075
|
+
logger: { log: this._log.bind(this) },
|
|
1076
|
+
replayMessage: (op) => `[POST-RESET] Replay detected for ${op.order_id}; skipping duplicate rebalance`
|
|
1077
|
+
});
|
|
1078
|
+
if (accountingResult.status === 'missing_key') {
|
|
1079
|
+
requiresOpenOrdersSync = true;
|
|
1080
|
+
continue;
|
|
1081
|
+
}
|
|
1082
|
+
if (accountingResult.status !== 'applied') {
|
|
1083
|
+
continue;
|
|
1084
|
+
}
|
|
1085
|
+
// Process this fill through the full rebalance pipeline
|
|
1086
|
+
// This will shift the boundary and place a new order on the filled slot
|
|
1087
|
+
const result = await this._processFillsWithBatching([gridOrder], new Set(), `[POST-RESET] fill ${gridOrder.id}`);
|
|
1088
|
+
if (result.aborted) {
|
|
1089
|
+
this._warn('[POST-RESET] Aborted batch due to illegal state; skipping grid persistence this cycle');
|
|
1090
|
+
continue;
|
|
1091
|
+
}
|
|
1084
1092
|
}
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
const result = await this._processFillsWithBatching([gridOrder], new Set(), `[POST-RESET] fill ${gridOrder.id}`);
|
|
1088
|
-
if (result.aborted) {
|
|
1089
|
-
this._warn('[POST-RESET] Aborted batch due to illegal state; skipping grid persistence this cycle');
|
|
1090
|
-
continue;
|
|
1093
|
+
finally {
|
|
1094
|
+
this.manager.unlockOrders([gridOrder.id]);
|
|
1091
1095
|
}
|
|
1092
1096
|
}
|
|
1093
1097
|
if (requiresOpenOrdersSync) {
|
|
@@ -1279,6 +1283,30 @@ class DEXBot {
|
|
|
1279
1283
|
await this._processFillsWithBootstrapMode(chainOrders);
|
|
1280
1284
|
}
|
|
1281
1285
|
this.manager.finishBootstrap();
|
|
1286
|
+
// Refresh account totals after bootstrap to eliminate the timing
|
|
1287
|
+
// gap between the initial balance fetch and grid operations (sync,
|
|
1288
|
+
// reconcile, fills). Without this, the first maintenance cycle sees
|
|
1289
|
+
// a fund drift (expected at bootstrap) and triggers an unnecessary
|
|
1290
|
+
// invariant violation + full recovery cycle.
|
|
1291
|
+
// Bound by a timeout to avoid blocking _fillProcessingLock on a
|
|
1292
|
+
// flaky node. If the fetch times out, continue with cached values;
|
|
1293
|
+
// the next periodic maintenance cycle will retry.
|
|
1294
|
+
const FETCH_TIMEOUT_MS = 30000;
|
|
1295
|
+
let _fetchTimeoutHandle;
|
|
1296
|
+
try {
|
|
1297
|
+
await Promise.race([
|
|
1298
|
+
this.manager.fetchAccountTotals(),
|
|
1299
|
+
new Promise((_, reject) => {
|
|
1300
|
+
_fetchTimeoutHandle = setTimeout(() => reject(new Error('timeout')), FETCH_TIMEOUT_MS);
|
|
1301
|
+
})
|
|
1302
|
+
]);
|
|
1303
|
+
}
|
|
1304
|
+
catch (fetchErr) {
|
|
1305
|
+
this._log(`[STARTUP] [${this.config?.botKey || 'unknown'}] fetchAccountTotals ${fetchErr.message === 'timeout' ? 'timed out' : 'failed'} (${fetchErr.message}). Continuing with cached account totals.`, 'warn');
|
|
1306
|
+
}
|
|
1307
|
+
finally {
|
|
1308
|
+
clearTimeout(_fetchTimeoutHandle);
|
|
1309
|
+
}
|
|
1282
1310
|
// Perform initial grid maintenance (thresholds, divergence, spread, health)
|
|
1283
1311
|
// Consolidated into shared logic to ensure consistent behavior at boot and runtime.
|
|
1284
1312
|
// CRITICAL: Pass lockAlreadyHeld since we're inside _fillProcessingLock.acquire()
|
|
@@ -1504,11 +1532,11 @@ class DEXBot {
|
|
|
1504
1532
|
try {
|
|
1505
1533
|
// BOOTSTRAP OPTIMIZATION: During bootstrap, prioritize fill processing over grid-wide checks
|
|
1506
1534
|
// Process fills immediately with side-only rebalancing (no expensive full grid recalculations)
|
|
1507
|
-
if (this.manager.
|
|
1535
|
+
if (this.manager.isBootstrapping()) {
|
|
1508
1536
|
// During bootstrap: skip lock contention checks, process fills directly
|
|
1509
1537
|
let bootstrapSkipped = false;
|
|
1510
1538
|
await this.manager._fillProcessingLock.acquire(async () => {
|
|
1511
|
-
if (!this.manager.
|
|
1539
|
+
if (!this.manager.isBootstrapping()) {
|
|
1512
1540
|
// Bootstrap finished while waiting for the lock — no
|
|
1513
1541
|
// work to do, but the iteration is still healthy.
|
|
1514
1542
|
bootstrapSkipped = true;
|
|
@@ -1542,10 +1570,12 @@ class DEXBot {
|
|
|
1542
1570
|
// fill cycle. It is re-set when orphan fills are credited,
|
|
1543
1571
|
// and consumed (set to null) on the next fund-invariant check
|
|
1544
1572
|
// in accounting.ts, which widens tolerance by 5x while set.
|
|
1573
|
+
// Written to this.manager (not this) because accounting.ts
|
|
1574
|
+
// reads from the OrderManager reference (mgr).
|
|
1545
1575
|
// Also cleared by _performStateRecovery after a fresh chain
|
|
1546
1576
|
// fetch. The timestamp value itself is not compared against a
|
|
1547
1577
|
// window — it acts as a consume-on-read boolean.
|
|
1548
|
-
this._orphanFillsCreditedAt = null;
|
|
1578
|
+
this.manager._orphanFillsCreditedAt = null;
|
|
1549
1579
|
while (this._incomingFillQueue.length > 0) {
|
|
1550
1580
|
const batchStartTime = Date.now();
|
|
1551
1581
|
// Track max queue depth
|
|
@@ -1610,9 +1640,9 @@ class DEXBot {
|
|
|
1610
1640
|
requiresOpenOrdersSync = true;
|
|
1611
1641
|
}
|
|
1612
1642
|
// Record orphan fill credit timestamp for fund invariant
|
|
1613
|
-
// tolerance widening.
|
|
1614
|
-
//
|
|
1615
|
-
this._orphanFillsCreditedAt = Date.now();
|
|
1643
|
+
// tolerance widening. Written to this.manager because
|
|
1644
|
+
// accounting.ts reads from the OrderManager (mgr).
|
|
1645
|
+
this.manager._orphanFillsCreditedAt = Date.now();
|
|
1616
1646
|
// Don't add to validFills - we can't do rebalancing without a grid slot
|
|
1617
1647
|
// But the funds are now credited, preventing fund invariant violation
|
|
1618
1648
|
continue;
|
|
@@ -1620,7 +1650,7 @@ class DEXBot {
|
|
|
1620
1650
|
// Process both maker and taker fills for our grid orders
|
|
1621
1651
|
// Grid validation ensures we only process fills belonging to our account
|
|
1622
1652
|
// Taker fills are included because the bot may execute market orders or act as taker
|
|
1623
|
-
const roleStr = fillOp.is_maker ? 'maker' : 'taker';
|
|
1653
|
+
const roleStr = fillOp.is_maker !== false ? 'maker' : 'taker';
|
|
1624
1654
|
this.manager.logger.log(`Processing ${roleStr} fill for order ${fillOp.order_id}`, 'debug');
|
|
1625
1655
|
const fillKey = buildFillKey(fill);
|
|
1626
1656
|
if (!fillKey) {
|
|
@@ -1727,6 +1757,12 @@ class DEXBot {
|
|
|
1727
1757
|
const sortedBlocks = [...fillsByBlock.keys()].sort((a, b) => a - b);
|
|
1728
1758
|
const accumulatedOrders = [];
|
|
1729
1759
|
let anyRequiresSync = false;
|
|
1760
|
+
// Capture whether any fill was skipped during validation
|
|
1761
|
+
// (e.g. missing history ID) and set the sync flag. The
|
|
1762
|
+
// per-block reset below would lose this state since those
|
|
1763
|
+
// fills were filtered out of validFills and never enter
|
|
1764
|
+
// any block group.
|
|
1765
|
+
const initialRequiresSync = requiresOpenOrdersSync;
|
|
1730
1766
|
for (const blockNum of sortedBlocks) {
|
|
1731
1767
|
// Reset requiresOpenOrdersSync per block group so one
|
|
1732
1768
|
// block's history-id gap doesn't force the next block
|
|
@@ -1738,12 +1774,24 @@ class DEXBot {
|
|
|
1738
1774
|
if (requiresOpenOrdersSync)
|
|
1739
1775
|
anyRequiresSync = true;
|
|
1740
1776
|
}
|
|
1741
|
-
|
|
1777
|
+
// Preserve both per-block sync flags and the initial flag
|
|
1778
|
+
// from filtered-out fills (missing history ID).
|
|
1779
|
+
requiresOpenOrdersSync = anyRequiresSync || initialRequiresSync;
|
|
1742
1780
|
if (fillsWithoutBlock.length > 0) {
|
|
1743
1781
|
this.manager.logger.log(`[FILL-BLOCK] Processing ${fillsWithoutBlock.length} fill(s) without block info`, 'debug');
|
|
1744
1782
|
const noBlockResult = await processValidFills(fillsWithoutBlock);
|
|
1745
1783
|
accumulatedOrders.push(...noBlockResult);
|
|
1746
1784
|
}
|
|
1785
|
+
// If a fill was filtered out during validation (e.g. missing
|
|
1786
|
+
// history ID) and no block group triggered the open-orders
|
|
1787
|
+
// sync, run it now so the grid state is reconciled.
|
|
1788
|
+
if (requiresOpenOrdersSync && !anyRequiresSync) {
|
|
1789
|
+
this.manager.logger.log('[FILL-BLOCK] Running open-orders sync for fills with missing history identifiers', 'warn');
|
|
1790
|
+
const fallbackOrders = await processValidFills([]);
|
|
1791
|
+
accumulatedOrders.push(...fallbackOrders);
|
|
1792
|
+
// Flag consumed — variable goes out of scope on
|
|
1793
|
+
// next while iteration.
|
|
1794
|
+
}
|
|
1747
1795
|
allFilledOrders = accumulatedOrders;
|
|
1748
1796
|
// 4. Handle Price Corrections
|
|
1749
1797
|
if (ordersNeedingCorrection.length > 0) {
|
|
@@ -1978,20 +2026,26 @@ class DEXBot {
|
|
|
1978
2026
|
if (trackedFillKey && !this._isNewFillKey(trackedFillKey, processedFillKeys, '[BOOTSTRAP]', fillOp.order_id)) {
|
|
1979
2027
|
continue;
|
|
1980
2028
|
}
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
2029
|
+
this.manager.lockOrders([gridOrder.id]);
|
|
2030
|
+
try {
|
|
2031
|
+
const accountingResult = await this._applyReplaySafeTrackedFillAccounting(fill, fillOp, {
|
|
2032
|
+
context: 'BOOTSTRAP',
|
|
2033
|
+
replayMessage: (op) => `[BOOTSTRAP] Replay detected for ${op.order_id}; skipping duplicate bootstrap rebalance`
|
|
2034
|
+
});
|
|
2035
|
+
if (accountingResult.status === 'missing_key') {
|
|
2036
|
+
requiresOpenOrdersSync = true;
|
|
2037
|
+
continue;
|
|
2038
|
+
}
|
|
2039
|
+
if (accountingResult.status !== 'applied') {
|
|
2040
|
+
continue;
|
|
2041
|
+
}
|
|
2042
|
+
validFills.push({ ...fill, gridOrder });
|
|
2043
|
+
const fillType = gridOrder.type === ORDER_TYPES.BUY ? 'BUY' : 'SELL';
|
|
2044
|
+
this._log(`[BOOTSTRAP] Fill detected: ${fillType} order (${fillOp.is_maker !== false ? 'maker' : 'taker'})`);
|
|
1988
2045
|
}
|
|
1989
|
-
|
|
1990
|
-
|
|
2046
|
+
finally {
|
|
2047
|
+
this.manager.unlockOrders([gridOrder.id]);
|
|
1991
2048
|
}
|
|
1992
|
-
validFills.push({ ...fill, gridOrder });
|
|
1993
|
-
const fillType = gridOrder.type === ORDER_TYPES.BUY ? 'BUY' : 'SELL';
|
|
1994
|
-
this._log(`[BOOTSTRAP] Fill detected: ${fillType} order (${fillOp.is_maker ? 'maker' : 'taker'})`);
|
|
1995
2049
|
}
|
|
1996
2050
|
if (requiresOpenOrdersSync) {
|
|
1997
2051
|
this._log('[BOOTSTRAP] Falling back to open-orders sync for fill(s) missing replay-safe history identifiers', 'warn');
|
|
@@ -2628,7 +2682,11 @@ class DEXBot {
|
|
|
2628
2682
|
fingerprint: entry.fingerprint
|
|
2629
2683
|
});
|
|
2630
2684
|
if (match) {
|
|
2631
|
-
adopted.push({
|
|
2685
|
+
adopted.push({
|
|
2686
|
+
slotId: entry.slotId,
|
|
2687
|
+
chainOrderId: match.id,
|
|
2688
|
+
orderType: entry.orderType || entry.order?.type,
|
|
2689
|
+
});
|
|
2632
2690
|
this.manager._pendingBroadcasts.delete(entry.fingerprint);
|
|
2633
2691
|
}
|
|
2634
2692
|
else {
|
|
@@ -2665,7 +2723,11 @@ class DEXBot {
|
|
|
2665
2723
|
fingerprint: entry.fingerprint
|
|
2666
2724
|
});
|
|
2667
2725
|
if (match) {
|
|
2668
|
-
adopted.push({
|
|
2726
|
+
adopted.push({
|
|
2727
|
+
slotId: entry.slotId,
|
|
2728
|
+
chainOrderId: match.id,
|
|
2729
|
+
orderType: entry.orderType || entry.order?.type,
|
|
2730
|
+
});
|
|
2669
2731
|
this.manager.logger.log(`[COW][UNCERTAIN] CREATE re-adopted after ${recheckRound} block(s): ` +
|
|
2670
2732
|
`${entry.slotId}->${match.id}`, 'info');
|
|
2671
2733
|
}
|
|
@@ -2748,27 +2810,27 @@ class DEXBot {
|
|
|
2748
2810
|
this.manager.logger.log(`[COW][UNCERTAIN] Auto-cancel pass failed: ${orphanErr?.message || orphanErr}`, 'warn');
|
|
2749
2811
|
}
|
|
2750
2812
|
// Boundary shift recovery: the COW batch that should have committed the
|
|
2751
|
-
// boundary shift from this fill cycle failed before commit.
|
|
2752
|
-
//
|
|
2753
|
-
//
|
|
2754
|
-
//
|
|
2755
|
-
//
|
|
2756
|
-
//
|
|
2813
|
+
// boundary shift from this fill cycle failed before commit. Only COUNT
|
|
2814
|
+
// ADOPTED CREATEs — orders that actually landed on-chain. Discarded
|
|
2815
|
+
// CREATEs represent orders that never existed, so the grid must NOT
|
|
2816
|
+
// shift the boundary for them. The next fill cycle's
|
|
2817
|
+
// calculateTargetGrid → deriveTargetBoundary will recompute the correct
|
|
2818
|
+
// boundary from scratch for any discarded slots.
|
|
2757
2819
|
//
|
|
2758
2820
|
// NOTE: Direct mutation of manager.boundaryIdx outside a COW commit
|
|
2759
2821
|
// violates the invariant stated in grid.ts:1217-1220 (boundary must only
|
|
2760
2822
|
// be updated atomically inside _commitWorkingGrid). This is intentional
|
|
2761
2823
|
// here because the COW commit already failed — the invariant was already
|
|
2762
2824
|
// broken by the broadcast uncertainty, and the adjustment only restores
|
|
2763
|
-
// the state to what the successful commit would have produced
|
|
2764
|
-
|
|
2825
|
+
// the state to what the successful commit would have produced for
|
|
2826
|
+
// orders that are confirmed on-chain.
|
|
2827
|
+
if (hadRotation && this.manager && adopted.length > 0) {
|
|
2765
2828
|
let boundaryShift = 0;
|
|
2766
|
-
for (const entry of
|
|
2767
|
-
|
|
2768
|
-
if (orderType === ORDER_TYPES.SELL) {
|
|
2829
|
+
for (const entry of adopted) {
|
|
2830
|
+
if (entry.orderType === ORDER_TYPES.SELL) {
|
|
2769
2831
|
boundaryShift--; // SELL CREATE → fill was BUY → boundary LEFT
|
|
2770
2832
|
}
|
|
2771
|
-
else if (orderType === ORDER_TYPES.BUY) {
|
|
2833
|
+
else if (entry.orderType === ORDER_TYPES.BUY) {
|
|
2772
2834
|
boundaryShift++; // BUY CREATE → fill was SELL → boundary RIGHT
|
|
2773
2835
|
}
|
|
2774
2836
|
}
|
|
@@ -2780,10 +2842,10 @@ class DEXBot {
|
|
|
2780
2842
|
if (newIdx !== oldIdx) {
|
|
2781
2843
|
this.manager.boundaryIdx = newIdx;
|
|
2782
2844
|
this.manager.logger.log(`[COW][UNCERTAIN] Boundary adjusted by ${boundaryShift} ` +
|
|
2783
|
-
`(${adopted.length} adopted
|
|
2845
|
+
`(${adopted.length} adopted CREATE(s), ${discarded.length} discarded): ` +
|
|
2784
2846
|
`${oldIdx} → ${newIdx}. Next COW cycle will generate replacement opposite-side orders.`, 'warn');
|
|
2785
2847
|
if (typeof this.manager._markGridDirty === 'function') {
|
|
2786
|
-
this.manager._markGridDirty(
|
|
2848
|
+
this.manager._markGridDirty();
|
|
2787
2849
|
}
|
|
2788
2850
|
}
|
|
2789
2851
|
}
|
|
@@ -3324,7 +3386,7 @@ class DEXBot {
|
|
|
3324
3386
|
if (this._credentialRecoveryInFlight || !this._credentialRecoveryNeeded || this._shuttingDown) {
|
|
3325
3387
|
return;
|
|
3326
3388
|
}
|
|
3327
|
-
if (this.manager?.
|
|
3389
|
+
if (this.manager?.isBootstrapping?.() || this.manager?.isBroadcastingActive?.()) {
|
|
3328
3390
|
if (!this._credentialRecoveryDeferredTimer) {
|
|
3329
3391
|
this.manager?.logger?.log?.('[CREDENTIAL] Deferring credential recovery until startup/broadcast activity is idle.', 'info');
|
|
3330
3392
|
this._credentialRecoveryDeferredTimer = setTimeout(() => {
|