Skip to content

Commit d12e9da

Browse files
committed
fix: prevent and resolve stale dust duplicates at the same price level
Two on-chain orders at the same grid level (e.g. slot-119 with 0.0006 dust remnant + slot-120 with the real 2.4052 order) were re-forming because the sync engine adopted orphan remnants into virtual slots, and the dust auto- cancel only targeted the top-of-window partial, leaving interior duplicates in place indefinitely. Four coordinated fixes close both the formation path and the persistence path. ## Sync engine: reject any orphan at a duplicate price level File: modules/order/sync_engine.ts - Problem: Pass-2 fallback adopted any orphan into a virtual/spread slot, including tiny remnants of replaced orders, creating a duplicate price level inside the active grid. - Impact: Visible as two on-chain orders at the same price (real order covered by a grid slot, dust remnant adopted into a different slot). - Solution: Before adopting an orphan, check if an active grid order of the same type already exists at the same price (within `calculatePriceTolerance` using `Math.max(size)` to keep tolerance tight). If so, the orphan is a duplicate — skip adoption and push to `unmatchedChainOrders` so the reconcile layer cancels it on chain. Size is irrelevant; any duplicate violates the grid invariant of one order per price level. ## Reconcile: cancel duplicate chain orders unconditionally File: modules/order/grid_reconcile.ts - Problem: SUSPECTED_DUPLICATE block logged the duplicate but never removed it from chain, so duplicates persisted across restarts. - Impact: Two on-chain orders at the same price level after every restart until manual intervention. - Solution: When an unmatched order is within `looseTolerance` of an active grid order, cancel it on chain via `_cancelChainOrder` with `releaseUntrackedFunds: true`. Cancelled IDs are filtered out of `unmatchedParsed` so `_reconcileStartupSide` doesn't reprocess them. No size guard — any duplicate at the same price is a violation. - Also removed `SUSPECTED_DUPLICATE_TOLERANCE_FLOOR = 0.01` — absolute price floor was wrong for low-price assets (BTS/USD: floor is 100% of price) and irrelevant for high-price assets. Now just `tolerance * SUSPECTED_DUPLICATE_TOLERANCE_MULTIPLIER`. ## Grid: dust detection covers interior partials with duplicate price level File: modules/order/grid.ts - Problem: `checkWindowDust` only flagged the top-of-window partial per side, so interior dust duplicates at the same price level as an active sibling were never detected for the `DUST_CANCEL_DELAY_SEC` auto-cancel. - Impact: Interior dust duplicates persisted indefinitely even when an active sibling at the same price made them safe to cancel (no gap). - Solution: Interior partials are eligible for dust detection if they share a price level with an active sibling (within `calculatePriceTolerance` using `Math.max(size)`). Top-of-window partials remain always eligible. Only ACTIVE siblings are checked — two PARTIALs sharing a price with no active sibling do not qualify; that gap is left to the rebalancer. ## Math helper documentation File: modules/order/utils/math.ts - Added doc note on `calculatePriceTolerance`: `orderSize` controls strictness (larger = tighter tolerance). For duplicate-price-level detection, always pass `Math.max(sizeA, sizeB)` to avoid a tiny dust order inflating the tolerance window and falsely matching distant prices. This makes the symmetric `Math.max`/`Math.min` usage in grid.ts and sync_engine.ts self-documenting. ## Testing Notes - Verified numerically for BTS/XRP @ 1079.67 (precision 5/5) that the old tolerance (orphan size 0.0006) was 18.01 for SELL / 19,450 for BUY, falsely matching an orphan at 1079.67 to a grid order at the next level (1085, +0.5%). New tolerance (`Math.max(0.0006, 2.4052)`) is 0.0045 / 4.85 and correctly rejects the false match. - tests/test_dust_rebalance_logic.ts — added `testInteriorDustWithDuplicatePriceLevel` (interior partial + active sibling at same price → eligible) and `testInteriorDustAdjacentGridLevelNotEligible` (partial at adjacent price → not eligible). - tests/test_sync_logic.ts — updated `testOrphanAtDuplicatePriceLevelIsNotAdopted` (orphan sharing price with active order → NOT adopted, spread slot stays virtual). - `npx tsc --noEmit` → clean. - All relevant tests pass.
1 parent 5cfe147 commit d12e9da

18 files changed

Lines changed: 276 additions & 44 deletions

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22

33
All notable changes to this project will be documented in this file.
44

5+
## [1.0.5] - 2026-07-01 - Grid Invariant Enforcement
6+
7+
### 2026-07-01
8+
9+
- **Fix**: prevent stale dust duplicates at the same price level — sync engine rejects orphan adoption when an active order already occupies that price (uses `Math.max(size)` for tight tolerance). Reconcile unconditionally cancels duplicate chain orders on chain via `_cancelChainOrder` with `releaseUntrackedFunds: true`. Dust detection expanded to interior partials sharing a price level with an active sibling. Three coordinated layers enforce "one order per grid price level" invariant (`modules/order/sync_engine.ts`, `modules/order/grid_reconcile.ts`, `modules/order/grid.ts`).
10+
- **Chore**: version bumped to 1.0.5 across all manifests.
11+
- **Docs**: updated `CHANGELOG.md`, `docs/EVOLUTION.md`, `docs/README.md`, `docs/DEXBOT_COMPARISON.md`, `docs/FUND_MOVEMENT_AND_ACCOUNTING.md`.
12+
513
## [1.0.4] - 2026-07-01 - Update Script Hardening & Stash Leak Fix
614

715
### 2026-07-01

analysis/ama_fitting/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ama_fitting",
3-
"version": "1.0.4",
3+
"version": "1.0.5",
44
"description": "Tools for fitting AMA parameters to market data",
55
"main": "../../dist/analysis/ama_fitting/optimizer_high_resolution.js",
66
"scripts": {

claw/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "dexbot2-claw",
3-
"version": "1.0.4",
3+
"version": "1.0.5",
44
"private": true,
55
"description": "Claw bridge and runtime integration layer for BitShares and DEXBot2.",
66
"type": "commonjs",

claw/runtimes/openclaw-plugin/openclaw.plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"id": "bitshares-claw",
33
"name": "BitShares Claw",
44
"description": "Native BitShares and DEXBot2 tools from the DEXBot2 claw integration",
5-
"version": "1.0.4",
5+
"version": "1.0.5",
66
"skills": [
77
"skills"
88
],
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "bitshares-claw-openclaw-plugin",
33
"private": true,
4-
"version": "1.0.4",
4+
"version": "1.0.5",
55
"type": "commonjs",
66
"main": "index.js"
77
}

claw/tests/test_claw_mcp_transport.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ async function testParserAcceptsJsonlAcrossChunksAndSingleBuffer() {
3030
capabilities: {},
3131
clientInfo: {
3232
name: 'claw-mcp-transport-test',
33-
version: '1.0.4'
33+
version: '1.0.5'
3434
},
3535
protocolVersion: '2024-11-05'
3636
}
@@ -181,7 +181,7 @@ async function testMainEntrypointHandlesRealProcessInitialize() {
181181
capabilities: {},
182182
clientInfo: {
183183
name: 'claw-mcp-transport-test',
184-
version: '1.0.4'
184+
version: '1.0.5'
185185
},
186186
protocolVersion: '2024-11-05'
187187
}

docs/DEXBOT_COMPARISON.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# DEXBot vs DEXBot2 — Detailed Comparison Report
22

33
> **Date:** 2026-06-16 *(metrics refreshed against local source trees)*
4-
> **Scope:** Full architectural, functional, and operational comparison between the original [DEXBot](https://github.com/Codaone/DEXBot) (Python, v1.0.0) and DEXBot2 (TypeScript, v1.0.4).
4+
> **Scope:** Full architectural, functional, and operational comparison between the original [DEXBot](https://github.com/Codaone/DEXBot) (Python, v1.0.0) and DEXBot2 (TypeScript, v1.0.5).
55
> **Audience:** Developers, contributors, and operators evaluating or migrating between the two projects.
66
77
---
@@ -36,7 +36,7 @@
3636

3737
| Attribute | DEXBot (original) | DEXBot2 |
3838
|---|---|---|
39-
| **Release Track** | 1.0.0 | v1.0.4 |
39+
| **Release Track** | 1.0.0 | v1.0.5 |
4040
| **Language** | Python 3.6+ | TypeScript 5.x |
4141
| **Status** | Released 1.0.0, unmaintained | Active development |
4242
| **Last Repo Activity** | May 23, 2020 | 2026-06-25 |
@@ -774,7 +774,7 @@ Where:
774774

775775
| Metric | DEXBot | DEXBot2 |
776776
|---|---|---|
777-
| **Release Track** | 1.0.0 | v1.0.4 |
777+
| **Release Track** | 1.0.0 | v1.0.5 |
778778
| **Active Since** | ~2018 | December 2025 |
779779
| **Last Commit** | May 23, 2020 | 2026-06-25 |
780780
| **Total Commits** | 2281 | 1659 at current HEAD |

docs/EVOLUTION.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22

33
## Executive Summary
44

5-
DEXBot2 is a sophisticated decentralized exchange trading bot for the BitShares blockchain. This report documents the complete evolution of the project from its inception in December 2025 through the current 1.0.4 stable release.
5+
DEXBot2 is a sophisticated decentralized exchange trading bot for the BitShares blockchain. This report documents the complete evolution of the project from its inception in December 2025 through the current 1.0.5 stable release.
66

77
### Key Milestones
88
- **Project Inception**: December 2, 2025
99
- **Growth Phase**: 1,600+ commits over ~6 active months
1010
- **Code Maturity**: Evolution from basic utilities to a ~58,000+ LoC intelligent TypeScript system
1111
- **Stability**: Progression from manual testing to a suite of 200+ automated test files
12-
- **Releases**: 39 release entries (v0.1.0 to v1.0.4)
12+
- **Releases**: 40 release entries (v0.1.0 to v1.0.5)
1313

1414
---
1515

@@ -170,6 +170,9 @@ Two-step candle gap repair in market adapter (auto-fill ≤24h, then Kibana), ma
170170
### v1.0.3 → v1.0.4 (2 commits)
171171
Update script hardening: daemon-downtime-after-update fix (pre-update state snapshot, TTY-gated auto-restart fallback), stash leak elimination (conditional push, apply+drop, auto-resolve with `--theirs`, conflicted `package-lock.json` regeneration). SIGUSR2 monolithic restart fix when `UPDATER.ACTIVE` is false — added local `pendingRestart` flag in `unlock.ts` independent of the updater.
172172

173+
### v1.0.4 → v1.0.5 (1 commit)
174+
Grid invariant enforcement: prevent stale dust duplicates at the same price level. Sync engine rejects orphan adoption when an active order already occupies that price (uses `Math.max(size)` for tight tolerance). Reconcile unconditionally cancels duplicate chain orders on chain. Dust detection expanded to interior partials sharing a price level with an active sibling. Three coordinated layers enforce "one order per grid price level" invariant.
175+
173176
---
174177

175178

@@ -218,7 +221,7 @@ DEXBot2 has matured from a basic grid bot into a signal-intelligent, production-
218221
---
219222

220223
**Report Originally Generated**: February 19, 2026
221-
**Last Updated**: July 1, 2026 (v1.0.4)
224+
**Last Updated**: July 1, 2026 (v1.0.5)
222225
**Total Commits**: 1661
223226
**Date Range**: December 2, 2025 - July 1, 2026 (ongoing)
224227
**Repository**: DEXBot2 (BitShares DEX Trading Bot)

docs/FUND_MOVEMENT_AND_ACCOUNTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -825,4 +825,4 @@ To prevent "Time-of-Check to Time-of-Use" errors:
825825
3. **Bootstrapping:** Fills arriving during startup (`isBootstrapping=true`) are queued until the grid is fully reconciled.
826826

827827
---
828-
*Technical Reference for DEXBot2 v1.0.4 release*
828+
*Technical Reference for DEXBot2 v1.0.5 release*

docs/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
This directory contains the comprehensive technical documentation for the DEXBot2 trading bot. It is designed to guide developers from high-level architecture down to the nuances of fund accounting and state management.
44

5-
**Version context:** v1.0.4 is the current release.
5+
**Version context:** v1.0.5 is the current release.
66

77
---
88

@@ -108,7 +108,7 @@ This directory contains the comprehensive technical documentation for the DEXBot
108108

109109
### 🧭 [Evolution Report](EVOLUTION.md)
110110
*Project timeline and major architecture phases.*
111-
- **Coverage**: Historical milestones from the initial December 2025 bootstrap through the v1.0.4 stable release, including credit maintenance hardening
111+
- **Coverage**: Historical milestones from the initial December 2025 bootstrap through the v1.0.5 stable release, including credit maintenance hardening
112112
- **Focus**: Architecture evolution, release history, test growth, and documentation changes
113113

114114
### 🗒️ [Changelog](../CHANGELOG.md)

0 commit comments

Comments
 (0)