dexbot 1.3.2 → 1.4.0

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 (738) hide show
  1. package/dist/analysis/chart_utils.d.ts +11 -9
  2. package/dist/analysis/chart_utils.d.ts.map +1 -1
  3. package/dist/analysis/chart_utils.js +21 -16
  4. package/dist/analysis/chart_utils.js.map +1 -1
  5. package/dist/analysis/math_utils.d.ts +4 -13
  6. package/dist/analysis/math_utils.d.ts.map +1 -1
  7. package/dist/analysis/math_utils.js +16 -18
  8. package/dist/analysis/math_utils.js.map +1 -1
  9. package/dist/analysis/tradingview/tradingview_uplot_chart_generator.d.ts +3 -7
  10. package/dist/analysis/tradingview/tradingview_uplot_chart_generator.d.ts.map +1 -1
  11. package/dist/analysis/tradingview/tradingview_uplot_chart_generator.js +38 -34
  12. package/dist/analysis/tradingview/tradingview_uplot_chart_generator.js.map +1 -1
  13. package/dist/analysis/trend_detection/hurst_analyzer.d.ts +1 -4
  14. package/dist/analysis/trend_detection/hurst_analyzer.d.ts.map +1 -1
  15. package/dist/analysis/trend_detection/hurst_analyzer.js +10 -7
  16. package/dist/analysis/trend_detection/hurst_analyzer.js.map +1 -1
  17. package/dist/analysis/trend_detection/kalman_trend_analyzer.d.ts +6 -6
  18. package/dist/analysis/trend_detection/kalman_trend_analyzer.d.ts.map +1 -1
  19. package/dist/analysis/trend_detection/kalman_trend_analyzer.js +23 -15
  20. package/dist/analysis/trend_detection/kalman_trend_analyzer.js.map +1 -1
  21. package/dist/analysis/trend_detection/kalman_velocity_smoothing.d.ts +12 -13
  22. package/dist/analysis/trend_detection/kalman_velocity_smoothing.d.ts.map +1 -1
  23. package/dist/analysis/trend_detection/kalman_velocity_smoothing.js +16 -16
  24. package/dist/analysis/trend_detection/kalman_velocity_smoothing.js.map +1 -1
  25. package/dist/analysis/trend_detection/permutation_entropy_analyzer.d.ts +1 -4
  26. package/dist/analysis/trend_detection/permutation_entropy_analyzer.d.ts.map +1 -1
  27. package/dist/analysis/trend_detection/permutation_entropy_analyzer.js +10 -7
  28. package/dist/analysis/trend_detection/permutation_entropy_analyzer.js.map +1 -1
  29. package/dist/bot.d.ts.map +1 -1
  30. package/dist/bot.js +6 -13
  31. package/dist/bot.js.map +1 -1
  32. package/dist/credential-daemon.d.ts.map +1 -1
  33. package/dist/credential-daemon.js +74 -35
  34. package/dist/credential-daemon.js.map +1 -1
  35. package/dist/dexbot.d.ts.map +1 -1
  36. package/dist/dexbot.js +16 -15
  37. package/dist/dexbot.js.map +1 -1
  38. package/dist/market_adapter/ama_signal_runner.d.ts +1 -1
  39. package/dist/market_adapter/ama_signal_runner.d.ts.map +1 -1
  40. package/dist/market_adapter/ama_signal_runner.js +8 -20
  41. package/dist/market_adapter/ama_signal_runner.js.map +1 -1
  42. package/dist/market_adapter/candle_utils.d.ts +2 -10
  43. package/dist/market_adapter/candle_utils.d.ts.map +1 -1
  44. package/dist/market_adapter/candle_utils.js +7 -8
  45. package/dist/market_adapter/candle_utils.js.map +1 -1
  46. package/dist/market_adapter/core/asymmetric_bounds.d.ts +12 -7
  47. package/dist/market_adapter/core/asymmetric_bounds.d.ts.map +1 -1
  48. package/dist/market_adapter/core/asymmetric_bounds.js +4 -5
  49. package/dist/market_adapter/core/asymmetric_bounds.js.map +1 -1
  50. package/dist/market_adapter/core/config_normalizers.d.ts +4 -9
  51. package/dist/market_adapter/core/config_normalizers.d.ts.map +1 -1
  52. package/dist/market_adapter/core/config_normalizers.js +9 -9
  53. package/dist/market_adapter/core/config_normalizers.js.map +1 -1
  54. package/dist/market_adapter/core/kibana_candles.d.ts +16 -20
  55. package/dist/market_adapter/core/kibana_candles.d.ts.map +1 -1
  56. package/dist/market_adapter/core/kibana_candles.js +16 -15
  57. package/dist/market_adapter/core/kibana_candles.js.map +1 -1
  58. package/dist/market_adapter/core/kibana_client.d.ts +8 -11
  59. package/dist/market_adapter/core/kibana_client.d.ts.map +1 -1
  60. package/dist/market_adapter/core/kibana_client.js +13 -11
  61. package/dist/market_adapter/core/kibana_client.js.map +1 -1
  62. package/dist/market_adapter/core/kibana_market_candles.d.ts +5 -12
  63. package/dist/market_adapter/core/kibana_market_candles.d.ts.map +1 -1
  64. package/dist/market_adapter/core/kibana_market_candles.js +12 -21
  65. package/dist/market_adapter/core/kibana_market_candles.js.map +1 -1
  66. package/dist/market_adapter/core/market_adapter_service.d.ts +75 -53
  67. package/dist/market_adapter/core/market_adapter_service.d.ts.map +1 -1
  68. package/dist/market_adapter/core/market_adapter_service.js +102 -98
  69. package/dist/market_adapter/core/market_adapter_service.js.map +1 -1
  70. package/dist/market_adapter/core/strategies/ama.d.ts +21 -1
  71. package/dist/market_adapter/core/strategies/ama.d.ts.map +1 -1
  72. package/dist/market_adapter/core/strategies/ama.js +10 -10
  73. package/dist/market_adapter/core/strategies/ama.js.map +1 -1
  74. package/dist/market_adapter/core/strategies/ama_slope_model.d.ts +7 -11
  75. package/dist/market_adapter/core/strategies/ama_slope_model.d.ts.map +1 -1
  76. package/dist/market_adapter/core/strategies/ama_slope_model.js +23 -30
  77. package/dist/market_adapter/core/strategies/ama_slope_model.js.map +1 -1
  78. package/dist/market_adapter/core/strategies/atr/calculator.d.ts +5 -4
  79. package/dist/market_adapter/core/strategies/atr/calculator.d.ts.map +1 -1
  80. package/dist/market_adapter/core/strategies/atr/calculator.js +5 -3
  81. package/dist/market_adapter/core/strategies/atr/calculator.js.map +1 -1
  82. package/dist/market_adapter/core/strategies/collateral_manager.d.ts +4 -7
  83. package/dist/market_adapter/core/strategies/collateral_manager.d.ts.map +1 -1
  84. package/dist/market_adapter/core/strategies/collateral_manager.js +5 -4
  85. package/dist/market_adapter/core/strategies/collateral_manager.js.map +1 -1
  86. package/dist/market_adapter/core/strategies/regime_gate.d.ts +11 -19
  87. package/dist/market_adapter/core/strategies/regime_gate.d.ts.map +1 -1
  88. package/dist/market_adapter/core/strategies/regime_gate.js +22 -22
  89. package/dist/market_adapter/core/strategies/regime_gate.js.map +1 -1
  90. package/dist/market_adapter/index.d.ts +24 -2
  91. package/dist/market_adapter/index.d.ts.map +1 -1
  92. package/dist/market_adapter/index.js +82 -56
  93. package/dist/market_adapter/index.js.map +1 -1
  94. package/dist/market_adapter/inputs/fetch_cex_synthetic_data.js +26 -37
  95. package/dist/market_adapter/inputs/fetch_cex_synthetic_data.js.map +1 -1
  96. package/dist/market_adapter/inputs/fetch_lp_data.d.ts +4 -12
  97. package/dist/market_adapter/inputs/fetch_lp_data.d.ts.map +1 -1
  98. package/dist/market_adapter/inputs/fetch_lp_data.js +100 -66
  99. package/dist/market_adapter/inputs/fetch_lp_data.js.map +1 -1
  100. package/dist/market_adapter/inputs/kibana_source.d.ts +4 -9
  101. package/dist/market_adapter/inputs/kibana_source.d.ts.map +1 -1
  102. package/dist/market_adapter/inputs/kibana_source.js +17 -18
  103. package/dist/market_adapter/inputs/kibana_source.js.map +1 -1
  104. package/dist/market_adapter/interval_utils.d.ts +1 -4
  105. package/dist/market_adapter/interval_utils.d.ts.map +1 -1
  106. package/dist/market_adapter/interval_utils.js +2 -3
  107. package/dist/market_adapter/interval_utils.js.map +1 -1
  108. package/dist/market_adapter/log_format.d.ts +1 -9
  109. package/dist/market_adapter/log_format.d.ts.map +1 -1
  110. package/dist/market_adapter/log_format.js +7 -8
  111. package/dist/market_adapter/log_format.js.map +1 -1
  112. package/dist/market_adapter/lp_chart_core.d.ts +1 -4
  113. package/dist/market_adapter/lp_chart_core.d.ts.map +1 -1
  114. package/dist/market_adapter/lp_chart_core.js +22 -20
  115. package/dist/market_adapter/lp_chart_core.js.map +1 -1
  116. package/dist/market_adapter/lp_chart_runner.d.ts +13 -24
  117. package/dist/market_adapter/lp_chart_runner.d.ts.map +1 -1
  118. package/dist/market_adapter/lp_chart_runner.js +58 -56
  119. package/dist/market_adapter/lp_chart_runner.js.map +1 -1
  120. package/dist/market_adapter/lp_chart_strategy_loader.d.ts +4 -17
  121. package/dist/market_adapter/lp_chart_strategy_loader.d.ts.map +1 -1
  122. package/dist/market_adapter/lp_chart_strategy_loader.js +36 -36
  123. package/dist/market_adapter/lp_chart_strategy_loader.js.map +1 -1
  124. package/dist/market_adapter/market_adapter.d.ts +51 -72
  125. package/dist/market_adapter/market_adapter.d.ts.map +1 -1
  126. package/dist/market_adapter/market_adapter.js +227 -192
  127. package/dist/market_adapter/market_adapter.js.map +1 -1
  128. package/dist/market_adapter/merge_lp_data.js +17 -16
  129. package/dist/market_adapter/merge_lp_data.js.map +1 -1
  130. package/dist/market_adapter/test_helpers.d.ts +9 -13
  131. package/dist/market_adapter/test_helpers.d.ts.map +1 -1
  132. package/dist/market_adapter/test_helpers.js +14 -14
  133. package/dist/market_adapter/test_helpers.js.map +1 -1
  134. package/dist/market_adapter/utils/adapter_client.d.ts +6 -14
  135. package/dist/market_adapter/utils/adapter_client.d.ts.map +1 -1
  136. package/dist/market_adapter/utils/adapter_client.js +16 -15
  137. package/dist/market_adapter/utils/adapter_client.js.map +1 -1
  138. package/dist/market_adapter/utils/atomic_write.d.ts +2 -5
  139. package/dist/market_adapter/utils/atomic_write.d.ts.map +1 -1
  140. package/dist/market_adapter/utils/atomic_write.js +5 -5
  141. package/dist/market_adapter/utils/atomic_write.js.map +1 -1
  142. package/dist/market_adapter/utils/chain.d.ts +19 -21
  143. package/dist/market_adapter/utils/chain.d.ts.map +1 -1
  144. package/dist/market_adapter/utils/chain.js +15 -16
  145. package/dist/market_adapter/utils/chain.js.map +1 -1
  146. package/dist/market_adapter/utils/data_discovery.d.ts +1 -4
  147. package/dist/market_adapter/utils/data_discovery.d.ts.map +1 -1
  148. package/dist/market_adapter/utils/data_discovery.js +10 -10
  149. package/dist/market_adapter/utils/data_discovery.js.map +1 -1
  150. package/dist/market_adapter/utils/dynamic_grid_snapshot.d.ts +1 -6
  151. package/dist/market_adapter/utils/dynamic_grid_snapshot.d.ts.map +1 -1
  152. package/dist/market_adapter/utils/dynamic_grid_snapshot.js +14 -14
  153. package/dist/market_adapter/utils/dynamic_grid_snapshot.js.map +1 -1
  154. package/dist/market_adapter/utils/file_lock.d.ts +1 -7
  155. package/dist/market_adapter/utils/file_lock.d.ts.map +1 -1
  156. package/dist/market_adapter/utils/file_lock.js +21 -25
  157. package/dist/market_adapter/utils/file_lock.js.map +1 -1
  158. package/dist/market_adapter/utils/native_history.d.ts +12 -12
  159. package/dist/market_adapter/utils/native_history.d.ts.map +1 -1
  160. package/dist/market_adapter/utils/native_history.js +15 -15
  161. package/dist/market_adapter/utils/native_history.js.map +1 -1
  162. package/dist/market_adapter/utils/paths.d.ts +2 -4
  163. package/dist/market_adapter/utils/paths.d.ts.map +1 -1
  164. package/dist/market_adapter/utils/paths.js +6 -5
  165. package/dist/market_adapter/utils/paths.js.map +1 -1
  166. package/dist/modules/account_bots.d.ts +7 -8
  167. package/dist/modules/account_bots.d.ts.map +1 -1
  168. package/dist/modules/account_bots.js +92 -114
  169. package/dist/modules/account_bots.js.map +1 -1
  170. package/dist/modules/account_orders.d.ts +5 -9
  171. package/dist/modules/account_orders.d.ts.map +1 -1
  172. package/dist/modules/account_orders.js +69 -32
  173. package/dist/modules/account_orders.js.map +1 -1
  174. package/dist/modules/authority_resolver.d.ts +32 -1
  175. package/dist/modules/authority_resolver.d.ts.map +1 -1
  176. package/dist/modules/authority_resolver.js +18 -12
  177. package/dist/modules/authority_resolver.js.map +1 -1
  178. package/dist/modules/bitshares-native/chain_client.d.ts +3 -8
  179. package/dist/modules/bitshares-native/chain_client.d.ts.map +1 -1
  180. package/dist/modules/bitshares-native/chain_client.js +21 -16
  181. package/dist/modules/bitshares-native/chain_client.js.map +1 -1
  182. package/dist/modules/bitshares-native/crypto/ecc.browser.d.ts +21 -29
  183. package/dist/modules/bitshares-native/crypto/ecc.browser.d.ts.map +1 -1
  184. package/dist/modules/bitshares-native/crypto/ecc.browser.js +72 -38
  185. package/dist/modules/bitshares-native/crypto/ecc.browser.js.map +1 -1
  186. package/dist/modules/bitshares-native/crypto/ecc.d.ts +9 -36
  187. package/dist/modules/bitshares-native/crypto/ecc.d.ts.map +1 -1
  188. package/dist/modules/bitshares-native/crypto/ecc.js +40 -83
  189. package/dist/modules/bitshares-native/crypto/ecc.js.map +1 -1
  190. package/dist/modules/bitshares-native/crypto/ecc_selector.d.ts +14 -1
  191. package/dist/modules/bitshares-native/crypto/ecc_selector.d.ts.map +1 -1
  192. package/dist/modules/bitshares-native/crypto/ecc_selector.js +5 -3
  193. package/dist/modules/bitshares-native/crypto/ecc_selector.js.map +1 -1
  194. package/dist/modules/bitshares-native/index.d.ts +10 -2
  195. package/dist/modules/bitshares-native/index.d.ts.map +1 -1
  196. package/dist/modules/bitshares-native/index.js +68 -31
  197. package/dist/modules/bitshares-native/index.js.map +1 -1
  198. package/dist/modules/bitshares-native/lru_cache.d.ts +1 -4
  199. package/dist/modules/bitshares-native/lru_cache.d.ts.map +1 -1
  200. package/dist/modules/bitshares-native/lru_cache.js +6 -3
  201. package/dist/modules/bitshares-native/lru_cache.js.map +1 -1
  202. package/dist/modules/bitshares-native/resolvers.d.ts +3 -6
  203. package/dist/modules/bitshares-native/resolvers.d.ts.map +1 -1
  204. package/dist/modules/bitshares-native/resolvers.js +11 -9
  205. package/dist/modules/bitshares-native/resolvers.js.map +1 -1
  206. package/dist/modules/bitshares-native/serial/chain_constants.d.ts +53 -55
  207. package/dist/modules/bitshares-native/serial/chain_constants.d.ts.map +1 -1
  208. package/dist/modules/bitshares-native/serial/chain_constants.js +28 -27
  209. package/dist/modules/bitshares-native/serial/chain_constants.js.map +1 -1
  210. package/dist/modules/bitshares-native/serial/index.d.ts +5 -9
  211. package/dist/modules/bitshares-native/serial/index.d.ts.map +1 -1
  212. package/dist/modules/bitshares-native/serial/index.js +46 -12
  213. package/dist/modules/bitshares-native/serial/index.js.map +1 -1
  214. package/dist/modules/bitshares-native/serial/operations.d.ts +102 -100
  215. package/dist/modules/bitshares-native/serial/operations.d.ts.map +1 -1
  216. package/dist/modules/bitshares-native/serial/operations.js +473 -471
  217. package/dist/modules/bitshares-native/serial/operations.js.map +1 -1
  218. package/dist/modules/bitshares-native/serial/serializer.d.ts +2 -7
  219. package/dist/modules/bitshares-native/serial/serializer.d.ts.map +1 -1
  220. package/dist/modules/bitshares-native/serial/serializer.js +8 -3
  221. package/dist/modules/bitshares-native/serial/serializer.js.map +1 -1
  222. package/dist/modules/bitshares-native/serial/types.d.ts +26 -41
  223. package/dist/modules/bitshares-native/serial/types.d.ts.map +1 -1
  224. package/dist/modules/bitshares-native/serial/types.js +76 -42
  225. package/dist/modules/bitshares-native/serial/types.js.map +1 -1
  226. package/dist/modules/bitshares-native/signing_client.d.ts +1 -5
  227. package/dist/modules/bitshares-native/signing_client.d.ts.map +1 -1
  228. package/dist/modules/bitshares-native/signing_client.js +49 -11
  229. package/dist/modules/bitshares-native/signing_client.js.map +1 -1
  230. package/dist/modules/bitshares-native/subscriptions.d.ts +1 -4
  231. package/dist/modules/bitshares-native/subscriptions.d.ts.map +1 -1
  232. package/dist/modules/bitshares-native/subscriptions.js +47 -84
  233. package/dist/modules/bitshares-native/subscriptions.js.map +1 -1
  234. package/dist/modules/bitshares-native/transport.d.ts +1 -8
  235. package/dist/modules/bitshares-native/transport.d.ts.map +1 -1
  236. package/dist/modules/bitshares-native/transport.js +22 -15
  237. package/dist/modules/bitshares-native/transport.js.map +1 -1
  238. package/dist/modules/bitshares-native/tx/builder.d.ts +3 -8
  239. package/dist/modules/bitshares-native/tx/builder.d.ts.map +1 -1
  240. package/dist/modules/bitshares-native/tx/builder.js +61 -23
  241. package/dist/modules/bitshares-native/tx/builder.js.map +1 -1
  242. package/dist/modules/bitshares-native/tx/tx_cache.d.ts +1 -8
  243. package/dist/modules/bitshares-native/tx/tx_cache.d.ts.map +1 -1
  244. package/dist/modules/bitshares-native/tx/tx_cache.js +21 -17
  245. package/dist/modules/bitshares-native/tx/tx_cache.js.map +1 -1
  246. package/dist/modules/bitshares_client.d.ts +12 -23
  247. package/dist/modules/bitshares_client.d.ts.map +1 -1
  248. package/dist/modules/bitshares_client.js +109 -56
  249. package/dist/modules/bitshares_client.js.map +1 -1
  250. package/dist/modules/bot_settings.d.ts +1 -13
  251. package/dist/modules/bot_settings.d.ts.map +1 -1
  252. package/dist/modules/bot_settings.js +34 -34
  253. package/dist/modules/bot_settings.js.map +1 -1
  254. package/dist/modules/bots_file_lock.d.ts +3 -9
  255. package/dist/modules/bots_file_lock.d.ts.map +1 -1
  256. package/dist/modules/bots_file_lock.js +8 -9
  257. package/dist/modules/bots_file_lock.js.map +1 -1
  258. package/dist/modules/chain_keys.d.ts +7 -39
  259. package/dist/modules/chain_keys.d.ts.map +1 -1
  260. package/dist/modules/chain_keys.js +126 -90
  261. package/dist/modules/chain_keys.js.map +1 -1
  262. package/dist/modules/chain_orders.d.ts +46 -52
  263. package/dist/modules/chain_orders.d.ts.map +1 -1
  264. package/dist/modules/chain_orders.js +152 -104
  265. package/dist/modules/chain_orders.js.map +1 -1
  266. package/dist/modules/config.d.ts +50 -57
  267. package/dist/modules/config.d.ts.map +1 -1
  268. package/dist/modules/config.js +28 -24
  269. package/dist/modules/config.js.map +1 -1
  270. package/dist/modules/constants.d.ts +492 -492
  271. package/dist/modules/constants.d.ts.map +1 -1
  272. package/dist/modules/constants.js +79 -39
  273. package/dist/modules/constants.js.map +1 -1
  274. package/dist/modules/cr_planner.d.ts +1 -13
  275. package/dist/modules/cr_planner.d.ts.map +1 -1
  276. package/dist/modules/cr_planner.js +28 -28
  277. package/dist/modules/cr_planner.js.map +1 -1
  278. package/dist/modules/credential_policy.d.ts +18 -33
  279. package/dist/modules/credential_policy.d.ts.map +1 -1
  280. package/dist/modules/credential_policy.js +114 -87
  281. package/dist/modules/credential_policy.js.map +1 -1
  282. package/dist/modules/credential_runtime.d.ts +11 -21
  283. package/dist/modules/credential_runtime.d.ts.map +1 -1
  284. package/dist/modules/credential_runtime.js +40 -40
  285. package/dist/modules/credential_runtime.js.map +1 -1
  286. package/dist/modules/credential_session_cache.d.ts +8 -8
  287. package/dist/modules/credential_session_cache.d.ts.map +1 -1
  288. package/dist/modules/credential_session_cache.js +41 -8
  289. package/dist/modules/credential_session_cache.js.map +1 -1
  290. package/dist/modules/credit_runtime.d.ts +51 -316
  291. package/dist/modules/credit_runtime.d.ts.map +1 -1
  292. package/dist/modules/credit_runtime.js +257 -183
  293. package/dist/modules/credit_runtime.js.map +1 -1
  294. package/dist/modules/crypto/browser_provider.js +6 -6
  295. package/dist/modules/crypto/browser_provider.js.map +1 -1
  296. package/dist/modules/crypto/index.d.ts.map +1 -1
  297. package/dist/modules/crypto/index.js +2 -0
  298. package/dist/modules/crypto/index.js.map +1 -1
  299. package/dist/modules/crypto/sync.js +3 -3
  300. package/dist/modules/crypto/sync.js.map +1 -1
  301. package/dist/modules/dexbot_class.d.ts +124 -73
  302. package/dist/modules/dexbot_class.d.ts.map +1 -1
  303. package/dist/modules/dexbot_class.js +198 -3577
  304. package/dist/modules/dexbot_class.js.map +1 -1
  305. package/dist/modules/dexbot_cow_runtime.d.ts +322 -0
  306. package/dist/modules/dexbot_cow_runtime.d.ts.map +1 -0
  307. package/dist/modules/dexbot_cow_runtime.js +1836 -0
  308. package/dist/modules/dexbot_cow_runtime.js.map +1 -0
  309. package/dist/modules/dexbot_credential_client.d.ts +5 -11
  310. package/dist/modules/dexbot_credential_client.d.ts.map +1 -1
  311. package/dist/modules/dexbot_credential_client.js +32 -30
  312. package/dist/modules/dexbot_credential_client.js.map +1 -1
  313. package/dist/modules/dexbot_fill_runtime.d.ts +47 -15
  314. package/dist/modules/dexbot_fill_runtime.d.ts.map +1 -1
  315. package/dist/modules/dexbot_fill_runtime.js +565 -22
  316. package/dist/modules/dexbot_fill_runtime.js.map +1 -1
  317. package/dist/modules/dexbot_maintenance_runtime.d.ts +79 -10
  318. package/dist/modules/dexbot_maintenance_runtime.d.ts.map +1 -1
  319. package/dist/modules/dexbot_maintenance_runtime.js +294 -55
  320. package/dist/modules/dexbot_maintenance_runtime.js.map +1 -1
  321. package/dist/modules/dexbot_startup_runtime.d.ts +26 -0
  322. package/dist/modules/dexbot_startup_runtime.d.ts.map +1 -0
  323. package/dist/modules/dexbot_startup_runtime.js +575 -0
  324. package/dist/modules/dexbot_startup_runtime.js.map +1 -0
  325. package/dist/modules/dexbot_state_recovery.d.ts +115 -0
  326. package/dist/modules/dexbot_state_recovery.d.ts.map +1 -0
  327. package/dist/modules/dexbot_state_recovery.js +431 -0
  328. package/dist/modules/dexbot_state_recovery.js.map +1 -0
  329. package/dist/modules/fund_registry.d.ts +1 -13
  330. package/dist/modules/fund_registry.d.ts.map +1 -1
  331. package/dist/modules/fund_registry.js +23 -22
  332. package/dist/modules/fund_registry.js.map +1 -1
  333. package/dist/modules/general_settings.d.ts +3 -7
  334. package/dist/modules/general_settings.d.ts.map +1 -1
  335. package/dist/modules/general_settings.js +15 -15
  336. package/dist/modules/general_settings.js.map +1 -1
  337. package/dist/modules/graceful_shutdown.d.ts +1 -6
  338. package/dist/modules/graceful_shutdown.d.ts.map +1 -1
  339. package/dist/modules/graceful_shutdown.js +19 -16
  340. package/dist/modules/graceful_shutdown.js.map +1 -1
  341. package/dist/modules/key_store.d.ts.map +1 -1
  342. package/dist/modules/key_store.js +53 -20
  343. package/dist/modules/key_store.js.map +1 -1
  344. package/dist/modules/launcher/bot_supervisor.d.ts +23 -66
  345. package/dist/modules/launcher/bot_supervisor.d.ts.map +1 -1
  346. package/dist/modules/launcher/bot_supervisor.js +115 -107
  347. package/dist/modules/launcher/bot_supervisor.js.map +1 -1
  348. package/dist/modules/launcher/child_env.d.ts +2 -5
  349. package/dist/modules/launcher/child_env.d.ts.map +1 -1
  350. package/dist/modules/launcher/child_env.js +4 -4
  351. package/dist/modules/launcher/child_env.js.map +1 -1
  352. package/dist/modules/launcher/credential_bootstrap.d.ts +4 -8
  353. package/dist/modules/launcher/credential_bootstrap.d.ts.map +1 -1
  354. package/dist/modules/launcher/credential_bootstrap.js +30 -26
  355. package/dist/modules/launcher/credential_bootstrap.js.map +1 -1
  356. package/dist/modules/launcher/credential_daemon.d.ts +8 -15
  357. package/dist/modules/launcher/credential_daemon.d.ts.map +1 -1
  358. package/dist/modules/launcher/credential_daemon.js +72 -41
  359. package/dist/modules/launcher/credential_daemon.js.map +1 -1
  360. package/dist/modules/launcher/credential_secret.d.ts +1 -4
  361. package/dist/modules/launcher/credential_secret.d.ts.map +1 -1
  362. package/dist/modules/launcher/credential_secret.js +36 -4
  363. package/dist/modules/launcher/credential_secret.js.map +1 -1
  364. package/dist/modules/launcher/foreign_cred_daemon.d.ts +32 -1
  365. package/dist/modules/launcher/foreign_cred_daemon.d.ts.map +1 -1
  366. package/dist/modules/launcher/foreign_cred_daemon.js +25 -28
  367. package/dist/modules/launcher/foreign_cred_daemon.js.map +1 -1
  368. package/dist/modules/launcher/headless_password.d.ts +1 -4
  369. package/dist/modules/launcher/headless_password.d.ts.map +1 -1
  370. package/dist/modules/launcher/headless_password.js +11 -11
  371. package/dist/modules/launcher/headless_password.js.map +1 -1
  372. package/dist/modules/launcher/launch_modes.d.ts +15 -14
  373. package/dist/modules/launcher/launch_modes.d.ts.map +1 -1
  374. package/dist/modules/launcher/launch_modes.js +8 -8
  375. package/dist/modules/launcher/launch_modes.js.map +1 -1
  376. package/dist/modules/launcher/market_adapter_runtime.d.ts +10 -19
  377. package/dist/modules/launcher/market_adapter_runtime.d.ts.map +1 -1
  378. package/dist/modules/launcher/market_adapter_runtime.js +33 -34
  379. package/dist/modules/launcher/market_adapter_runtime.js.map +1 -1
  380. package/dist/modules/launcher/market_adapter_watchdog.d.ts +10 -17
  381. package/dist/modules/launcher/market_adapter_watchdog.d.ts.map +1 -1
  382. package/dist/modules/launcher/market_adapter_watchdog.js +42 -39
  383. package/dist/modules/launcher/market_adapter_watchdog.js.map +1 -1
  384. package/dist/modules/launcher/monolithic_runtime.d.ts +28 -57
  385. package/dist/modules/launcher/monolithic_runtime.d.ts.map +1 -1
  386. package/dist/modules/launcher/monolithic_runtime.js +135 -108
  387. package/dist/modules/launcher/monolithic_runtime.js.map +1 -1
  388. package/dist/modules/launcher/runtime_entry.d.ts +5 -10
  389. package/dist/modules/launcher/runtime_entry.d.ts.map +1 -1
  390. package/dist/modules/launcher/runtime_entry.js +14 -14
  391. package/dist/modules/launcher/runtime_entry.js.map +1 -1
  392. package/dist/modules/launcher/status_reporting.d.ts +17 -37
  393. package/dist/modules/launcher/status_reporting.d.ts.map +1 -1
  394. package/dist/modules/launcher/status_reporting.js +35 -34
  395. package/dist/modules/launcher/status_reporting.js.map +1 -1
  396. package/dist/modules/launcher/supervisor_control.d.ts +1 -4
  397. package/dist/modules/launcher/supervisor_control.d.ts.map +1 -1
  398. package/dist/modules/launcher/supervisor_control.js +9 -4
  399. package/dist/modules/launcher/supervisor_control.js.map +1 -1
  400. package/dist/modules/logger.d.ts +3 -1
  401. package/dist/modules/logger.d.ts.map +1 -1
  402. package/dist/modules/logger.js +38 -28
  403. package/dist/modules/logger.js.map +1 -1
  404. package/dist/modules/market_adapter_whitelist.d.ts +2 -10
  405. package/dist/modules/market_adapter_whitelist.d.ts.map +1 -1
  406. package/dist/modules/market_adapter_whitelist.js +18 -16
  407. package/dist/modules/market_adapter_whitelist.js.map +1 -1
  408. package/dist/modules/node_health_cache.d.ts +2 -12
  409. package/dist/modules/node_health_cache.d.ts.map +1 -1
  410. package/dist/modules/node_health_cache.js +24 -24
  411. package/dist/modules/node_health_cache.js.map +1 -1
  412. package/dist/modules/node_manager.d.ts +1 -1
  413. package/dist/modules/node_manager.d.ts.map +1 -1
  414. package/dist/modules/node_manager.js +44 -38
  415. package/dist/modules/node_manager.js.map +1 -1
  416. package/dist/modules/order/accounting.d.ts +12 -12
  417. package/dist/modules/order/accounting.d.ts.map +1 -1
  418. package/dist/modules/order/accounting.js +111 -76
  419. package/dist/modules/order/accounting.js.map +1 -1
  420. package/dist/modules/order/async_lock.d.ts +1 -2
  421. package/dist/modules/order/async_lock.d.ts.map +1 -1
  422. package/dist/modules/order/async_lock.js +4 -4
  423. package/dist/modules/order/async_lock.js.map +1 -1
  424. package/dist/modules/order/export.d.ts +8 -14
  425. package/dist/modules/order/export.d.ts.map +1 -1
  426. package/dist/modules/order/export.js +77 -42
  427. package/dist/modules/order/export.js.map +1 -1
  428. package/dist/modules/order/format.d.ts +17 -22
  429. package/dist/modules/order/format.d.ts.map +1 -1
  430. package/dist/modules/order/format.js +25 -31
  431. package/dist/modules/order/format.js.map +1 -1
  432. package/dist/modules/order/grid.d.ts +18 -104
  433. package/dist/modules/order/grid.d.ts.map +1 -1
  434. package/dist/modules/order/grid.js +246 -188
  435. package/dist/modules/order/grid.js.map +1 -1
  436. package/dist/modules/order/grid_reconcile.d.ts +8 -8
  437. package/dist/modules/order/grid_reconcile.d.ts.map +1 -1
  438. package/dist/modules/order/grid_reconcile.js +24 -24
  439. package/dist/modules/order/grid_reconcile.js.map +1 -1
  440. package/dist/modules/order/grid_reconcile_internal.d.ts +224 -1
  441. package/dist/modules/order/grid_reconcile_internal.d.ts.map +1 -1
  442. package/dist/modules/order/grid_reconcile_internal.js +145 -72
  443. package/dist/modules/order/grid_reconcile_internal.js.map +1 -1
  444. package/dist/modules/order/index.d.ts +1 -1
  445. package/dist/modules/order/index.d.ts.map +1 -1
  446. package/dist/modules/order/index.js +42 -7
  447. package/dist/modules/order/index.js.map +1 -1
  448. package/dist/modules/order/logger.d.ts +6 -16
  449. package/dist/modules/order/logger.d.ts.map +1 -1
  450. package/dist/modules/order/logger.js +76 -53
  451. package/dist/modules/order/logger.js.map +1 -1
  452. package/dist/modules/order/logger_state.d.ts +4 -4
  453. package/dist/modules/order/logger_state.d.ts.map +1 -1
  454. package/dist/modules/order/logger_state.js +3 -1
  455. package/dist/modules/order/logger_state.js.map +1 -1
  456. package/dist/modules/order/manager.d.ts +160 -37
  457. package/dist/modules/order/manager.d.ts.map +1 -1
  458. package/dist/modules/order/manager.js +166 -128
  459. package/dist/modules/order/manager.js.map +1 -1
  460. package/dist/modules/order/processed_fill_store.d.ts +6 -10
  461. package/dist/modules/order/processed_fill_store.d.ts.map +1 -1
  462. package/dist/modules/order/processed_fill_store.js +10 -9
  463. package/dist/modules/order/processed_fill_store.js.map +1 -1
  464. package/dist/modules/order/strategy.d.ts +3 -3
  465. package/dist/modules/order/strategy.d.ts.map +1 -1
  466. package/dist/modules/order/strategy.js +29 -27
  467. package/dist/modules/order/strategy.js.map +1 -1
  468. package/dist/modules/order/sync_engine.d.ts +9 -19
  469. package/dist/modules/order/sync_engine.d.ts.map +1 -1
  470. package/dist/modules/order/sync_engine.js +176 -126
  471. package/dist/modules/order/sync_engine.js.map +1 -1
  472. package/dist/modules/order/utils/math.d.ts +55 -85
  473. package/dist/modules/order/utils/math.d.ts.map +1 -1
  474. package/dist/modules/order/utils/math.js +155 -88
  475. package/dist/modules/order/utils/math.js.map +1 -1
  476. package/dist/modules/order/utils/order.d.ts +27 -72
  477. package/dist/modules/order/utils/order.d.ts.map +1 -1
  478. package/dist/modules/order/utils/order.js +144 -105
  479. package/dist/modules/order/utils/order.js.map +1 -1
  480. package/dist/modules/order/utils/system.d.ts +74 -44
  481. package/dist/modules/order/utils/system.d.ts.map +1 -1
  482. package/dist/modules/order/utils/system.js +188 -149
  483. package/dist/modules/order/utils/system.js.map +1 -1
  484. package/dist/modules/order/utils/validate.d.ts +21 -43
  485. package/dist/modules/order/utils/validate.d.ts.map +1 -1
  486. package/dist/modules/order/utils/validate.js +140 -110
  487. package/dist/modules/order/utils/validate.js.map +1 -1
  488. package/dist/modules/order/working_grid.d.ts +1 -4
  489. package/dist/modules/order/working_grid.d.ts.map +1 -1
  490. package/dist/modules/order/working_grid.js +9 -7
  491. package/dist/modules/order/working_grid.js.map +1 -1
  492. package/dist/modules/path_api.js +2 -2
  493. package/dist/modules/path_api.js.map +1 -1
  494. package/dist/modules/paths.d.ts +51 -55
  495. package/dist/modules/paths.d.ts.map +1 -1
  496. package/dist/modules/paths.js +72 -52
  497. package/dist/modules/paths.js.map +1 -1
  498. package/dist/modules/process_discovery.d.ts +1 -1
  499. package/dist/modules/process_discovery.d.ts.map +1 -1
  500. package/dist/modules/process_discovery.js +7 -7
  501. package/dist/modules/process_discovery.js.map +1 -1
  502. package/dist/modules/runtime.d.ts +1 -1
  503. package/dist/modules/runtime.d.ts.map +1 -1
  504. package/dist/modules/runtime.js +4 -4
  505. package/dist/modules/runtime.js.map +1 -1
  506. package/dist/modules/runtime_settings.d.ts +1 -0
  507. package/dist/modules/runtime_settings.d.ts.map +1 -1
  508. package/dist/modules/runtime_settings.js +15 -10
  509. package/dist/modules/runtime_settings.js.map +1 -1
  510. package/dist/modules/settings_merge.d.ts +1 -4
  511. package/dist/modules/settings_merge.d.ts.map +1 -1
  512. package/dist/modules/settings_merge.js +2 -1
  513. package/dist/modules/settings_merge.js.map +1 -1
  514. package/dist/modules/storage/browser_adapter.d.ts +7 -3
  515. package/dist/modules/storage/browser_adapter.d.ts.map +1 -1
  516. package/dist/modules/storage/browser_adapter.js +2 -0
  517. package/dist/modules/storage/browser_adapter.js.map +1 -1
  518. package/dist/modules/storage/index.d.ts +2 -2
  519. package/dist/modules/storage/index.d.ts.map +1 -1
  520. package/dist/modules/storage/index.js +2 -5
  521. package/dist/modules/storage/index.js.map +1 -1
  522. package/dist/modules/storage/node_adapter.d.ts +3 -3
  523. package/dist/modules/storage/node_adapter.d.ts.map +1 -1
  524. package/dist/modules/storage/node_adapter.js +9 -7
  525. package/dist/modules/storage/node_adapter.js.map +1 -1
  526. package/dist/modules/storage/types.d.ts +13 -10
  527. package/dist/modules/storage/types.d.ts.map +1 -1
  528. package/dist/modules/types.d.ts +0 -2
  529. package/dist/modules/types.d.ts.map +1 -1
  530. package/dist/modules/utils/base58check.d.ts +1 -9
  531. package/dist/modules/utils/base58check.d.ts.map +1 -1
  532. package/dist/modules/utils/base58check.js +14 -16
  533. package/dist/modules/utils/base58check.js.map +1 -1
  534. package/dist/modules/utils/build_dir.d.ts +2 -5
  535. package/dist/modules/utils/build_dir.d.ts.map +1 -1
  536. package/dist/modules/utils/build_dir.js +6 -3
  537. package/dist/modules/utils/build_dir.js.map +1 -1
  538. package/dist/modules/utils/errors.d.ts +2 -0
  539. package/dist/modules/utils/errors.d.ts.map +1 -0
  540. package/dist/modules/utils/errors.js +12 -0
  541. package/dist/modules/utils/errors.js.map +1 -0
  542. package/dist/modules/utils/fs_utils.d.ts +1 -8
  543. package/dist/modules/utils/fs_utils.d.ts.map +1 -1
  544. package/dist/modules/utils/fs_utils.js +8 -3
  545. package/dist/modules/utils/fs_utils.js.map +1 -1
  546. package/dist/modules/utils/math_utils.d.ts +2 -6
  547. package/dist/modules/utils/math_utils.d.ts.map +1 -1
  548. package/dist/modules/utils/math_utils.js +6 -2
  549. package/dist/modules/utils/math_utils.js.map +1 -1
  550. package/dist/modules/validate_profiles.d.ts +1 -11
  551. package/dist/modules/validate_profiles.d.ts.map +1 -1
  552. package/dist/modules/validate_profiles.js +25 -27
  553. package/dist/modules/validate_profiles.js.map +1 -1
  554. package/dist/pm2.d.ts +7 -6
  555. package/dist/pm2.d.ts.map +1 -1
  556. package/dist/pm2.js +132 -106
  557. package/dist/pm2.js.map +1 -1
  558. package/dist/scripts/analyze-git.d.ts.map +1 -1
  559. package/dist/scripts/analyze-git.js +15 -11
  560. package/dist/scripts/analyze-git.js.map +1 -1
  561. package/dist/scripts/analyze-orders.d.ts +146 -1
  562. package/dist/scripts/analyze-orders.d.ts.map +1 -1
  563. package/dist/scripts/analyze-orders.js +81 -105
  564. package/dist/scripts/analyze-orders.js.map +1 -1
  565. package/dist/scripts/diagnose-pool-history.d.ts.map +1 -1
  566. package/dist/scripts/diagnose-pool-history.js +9 -8
  567. package/dist/scripts/diagnose-pool-history.js.map +1 -1
  568. package/dist/scripts/divergence-calc.d.ts.map +1 -1
  569. package/dist/scripts/divergence-calc.js +11 -8
  570. package/dist/scripts/divergence-calc.js.map +1 -1
  571. package/dist/scripts/fix-err-message.d.ts +3 -0
  572. package/dist/scripts/fix-err-message.d.ts.map +1 -0
  573. package/dist/scripts/fix-err-message.js +198 -0
  574. package/dist/scripts/fix-err-message.js.map +1 -0
  575. package/dist/scripts/generate_lp_chart.d.ts +2 -9
  576. package/dist/scripts/generate_lp_chart.d.ts.map +1 -1
  577. package/dist/scripts/generate_lp_chart.js +14 -10
  578. package/dist/scripts/generate_lp_chart.js.map +1 -1
  579. package/dist/scripts/generate_mainnet_corpus_report.js +4 -4
  580. package/dist/scripts/generate_mainnet_corpus_report.js.map +1 -1
  581. package/dist/scripts/generate_market_adapter_whitelist.d.ts +17 -1
  582. package/dist/scripts/generate_market_adapter_whitelist.d.ts.map +1 -1
  583. package/dist/scripts/generate_market_adapter_whitelist.js +23 -20
  584. package/dist/scripts/generate_market_adapter_whitelist.js.map +1 -1
  585. package/dist/scripts/migrate_bot_keys.d.ts +1 -4
  586. package/dist/scripts/migrate_bot_keys.d.ts.map +1 -1
  587. package/dist/scripts/migrate_bot_keys.js +48 -124
  588. package/dist/scripts/migrate_bot_keys.js.map +1 -1
  589. package/dist/scripts/native_release_gates.d.ts.map +1 -1
  590. package/dist/scripts/native_release_gates.js +18 -14
  591. package/dist/scripts/native_release_gates.js.map +1 -1
  592. package/dist/scripts/print_grid.js +1 -1
  593. package/dist/scripts/print_grid.js.map +1 -1
  594. package/dist/scripts/run-tests.js +1 -0
  595. package/dist/scripts/run-tests.js.map +1 -1
  596. package/dist/scripts/runner.d.ts +1 -11
  597. package/dist/scripts/runner.d.ts.map +1 -1
  598. package/dist/scripts/runner.js +21 -19
  599. package/dist/scripts/runner.js.map +1 -1
  600. package/dist/scripts/test-credit-renewal.d.ts.map +1 -1
  601. package/dist/scripts/test-credit-renewal.js +2 -1
  602. package/dist/scripts/test-credit-renewal.js.map +1 -1
  603. package/dist/scripts/update.d.ts.map +1 -1
  604. package/dist/scripts/update.js +85 -79
  605. package/dist/scripts/update.js.map +1 -1
  606. package/dist/scripts/validate_bots.js +2 -2
  607. package/dist/scripts/validate_bots.js.map +1 -1
  608. package/dist/scripts/verify-browser-bundle.js +25 -1
  609. package/dist/scripts/verify-browser-bundle.js.map +1 -1
  610. package/dist/unlock.d.ts +4 -17
  611. package/dist/unlock.d.ts.map +1 -1
  612. package/dist/unlock.js +141 -108
  613. package/dist/unlock.js.map +1 -1
  614. package/package.json +7 -2
  615. package/dist/analysis/ama_fitting/analyze_ama_price_changes.d.ts +0 -3
  616. package/dist/analysis/ama_fitting/analyze_ama_price_changes.d.ts.map +0 -1
  617. package/dist/analysis/ama_fitting/analyze_ama_price_changes.js +0 -149
  618. package/dist/analysis/ama_fitting/analyze_ama_price_changes.js.map +0 -1
  619. package/dist/analysis/ama_fitting/analyze_lambda_vs_slow.d.ts +0 -3
  620. package/dist/analysis/ama_fitting/analyze_lambda_vs_slow.d.ts.map +0 -1
  621. package/dist/analysis/ama_fitting/analyze_lambda_vs_slow.js +0 -387
  622. package/dist/analysis/ama_fitting/analyze_lambda_vs_slow.js.map +0 -1
  623. package/dist/analysis/ama_fitting/calibrate_convergence_er.d.ts +0 -3
  624. package/dist/analysis/ama_fitting/calibrate_convergence_er.d.ts.map +0 -1
  625. package/dist/analysis/ama_fitting/calibrate_convergence_er.js +0 -200
  626. package/dist/analysis/ama_fitting/calibrate_convergence_er.js.map +0 -1
  627. package/dist/analysis/ama_fitting/fetch_lp_candles.d.ts +0 -3
  628. package/dist/analysis/ama_fitting/fetch_lp_candles.d.ts.map +0 -1
  629. package/dist/analysis/ama_fitting/fetch_lp_candles.js +0 -212
  630. package/dist/analysis/ama_fitting/fetch_lp_candles.js.map +0 -1
  631. package/dist/analysis/ama_fitting/generate_unified_comparison_chart.d.ts +0 -31
  632. package/dist/analysis/ama_fitting/generate_unified_comparison_chart.d.ts.map +0 -1
  633. package/dist/analysis/ama_fitting/generate_unified_comparison_chart.js +0 -249
  634. package/dist/analysis/ama_fitting/generate_unified_comparison_chart.js.map +0 -1
  635. package/dist/analysis/ama_fitting/optimizer_high_resolution.d.ts +0 -2
  636. package/dist/analysis/ama_fitting/optimizer_high_resolution.d.ts.map +0 -1
  637. package/dist/analysis/ama_fitting/optimizer_high_resolution.js +0 -782
  638. package/dist/analysis/ama_fitting/optimizer_high_resolution.js.map +0 -1
  639. package/dist/analysis/analyze_derivatives.d.ts +0 -95
  640. package/dist/analysis/analyze_derivatives.d.ts.map +0 -1
  641. package/dist/analysis/analyze_derivatives.js +0 -295
  642. package/dist/analysis/analyze_derivatives.js.map +0 -1
  643. package/dist/analysis/analyze_dynamic_weight.d.ts +0 -14
  644. package/dist/analysis/analyze_dynamic_weight.d.ts.map +0 -1
  645. package/dist/analysis/analyze_dynamic_weight.js +0 -207
  646. package/dist/analysis/analyze_dynamic_weight.js.map +0 -1
  647. package/dist/analysis/analyze_kalman.d.ts +0 -13
  648. package/dist/analysis/analyze_kalman.d.ts.map +0 -1
  649. package/dist/analysis/analyze_kalman.js +0 -123
  650. package/dist/analysis/analyze_kalman.js.map +0 -1
  651. package/dist/analysis/analyze_regime.d.ts +0 -20
  652. package/dist/analysis/analyze_regime.d.ts.map +0 -1
  653. package/dist/analysis/analyze_regime.js +0 -139
  654. package/dist/analysis/analyze_regime.js.map +0 -1
  655. package/dist/analysis/analyze_regime_windows.d.ts +0 -19
  656. package/dist/analysis/analyze_regime_windows.d.ts.map +0 -1
  657. package/dist/analysis/analyze_regime_windows.js +0 -413
  658. package/dist/analysis/analyze_regime_windows.js.map +0 -1
  659. package/dist/analysis/analyze_risk_profile.d.ts +0 -3
  660. package/dist/analysis/analyze_risk_profile.d.ts.map +0 -1
  661. package/dist/analysis/analyze_risk_profile.js +0 -159
  662. package/dist/analysis/analyze_risk_profile.js.map +0 -1
  663. package/dist/analysis/analyze_trade_heatmap.d.ts +0 -3
  664. package/dist/analysis/analyze_trade_heatmap.d.ts.map +0 -1
  665. package/dist/analysis/analyze_trade_heatmap.js +0 -367
  666. package/dist/analysis/analyze_trade_heatmap.js.map +0 -1
  667. package/dist/analysis/analyze_volatility.d.ts +0 -22
  668. package/dist/analysis/analyze_volatility.d.ts.map +0 -1
  669. package/dist/analysis/analyze_volatility.js +0 -172
  670. package/dist/analysis/analyze_volatility.js.map +0 -1
  671. package/dist/analysis/bot_fitting/backtest_ama_sweep.d.ts +0 -99
  672. package/dist/analysis/bot_fitting/backtest_ama_sweep.d.ts.map +0 -1
  673. package/dist/analysis/bot_fitting/backtest_ama_sweep.js +0 -804
  674. package/dist/analysis/bot_fitting/backtest_ama_sweep.js.map +0 -1
  675. package/dist/analysis/bot_fitting/backtest_bot_fitting.d.ts +0 -2
  676. package/dist/analysis/bot_fitting/backtest_bot_fitting.d.ts.map +0 -1
  677. package/dist/analysis/bot_fitting/backtest_bot_fitting.js +0 -347
  678. package/dist/analysis/bot_fitting/backtest_bot_fitting.js.map +0 -1
  679. package/dist/analysis/bot_fitting/shared_utils.d.ts +0 -15
  680. package/dist/analysis/bot_fitting/shared_utils.d.ts.map +0 -1
  681. package/dist/analysis/bot_fitting/shared_utils.js +0 -48
  682. package/dist/analysis/bot_fitting/shared_utils.js.map +0 -1
  683. package/dist/analysis/bot_key_utils.d.ts +0 -22
  684. package/dist/analysis/bot_key_utils.d.ts.map +0 -1
  685. package/dist/analysis/bot_key_utils.js +0 -162
  686. package/dist/analysis/bot_key_utils.js.map +0 -1
  687. package/dist/analysis/bot_usage/discover_bot_accounts.d.ts +0 -3
  688. package/dist/analysis/bot_usage/discover_bot_accounts.d.ts.map +0 -1
  689. package/dist/analysis/bot_usage/discover_bot_accounts.js +0 -498
  690. package/dist/analysis/bot_usage/discover_bot_accounts.js.map +0 -1
  691. package/dist/analysis/bot_usage/kibana_bot_queries.d.ts +0 -546
  692. package/dist/analysis/bot_usage/kibana_bot_queries.d.ts.map +0 -1
  693. package/dist/analysis/bot_usage/kibana_bot_queries.js +0 -427
  694. package/dist/analysis/bot_usage/kibana_bot_queries.js.map +0 -1
  695. package/dist/analysis/derivative_chart_generator.d.ts +0 -18
  696. package/dist/analysis/derivative_chart_generator.d.ts.map +0 -1
  697. package/dist/analysis/derivative_chart_generator.js +0 -896
  698. package/dist/analysis/derivative_chart_generator.js.map +0 -1
  699. package/dist/analysis/price_sources.d.ts +0 -34
  700. package/dist/analysis/price_sources.d.ts.map +0 -1
  701. package/dist/analysis/price_sources.js +0 -103
  702. package/dist/analysis/price_sources.js.map +0 -1
  703. package/dist/analysis/trade_profitability.d.ts +0 -115
  704. package/dist/analysis/trade_profitability.d.ts.map +0 -1
  705. package/dist/analysis/trade_profitability.js +0 -1247
  706. package/dist/analysis/trade_profitability.js.map +0 -1
  707. package/dist/analysis/tradingview/analyze_tradingview.d.ts +0 -36
  708. package/dist/analysis/tradingview/analyze_tradingview.d.ts.map +0 -1
  709. package/dist/analysis/tradingview/analyze_tradingview.js +0 -172
  710. package/dist/analysis/tradingview/analyze_tradingview.js.map +0 -1
  711. package/dist/analysis/trend_detection/derivative_analyzer.d.ts +0 -250
  712. package/dist/analysis/trend_detection/derivative_analyzer.d.ts.map +0 -1
  713. package/dist/analysis/trend_detection/derivative_analyzer.js +0 -903
  714. package/dist/analysis/trend_detection/derivative_analyzer.js.map +0 -1
  715. package/dist/analysis/trend_detection/dynamic_weight_chart_generator.d.ts +0 -6
  716. package/dist/analysis/trend_detection/dynamic_weight_chart_generator.d.ts.map +0 -1
  717. package/dist/analysis/trend_detection/dynamic_weight_chart_generator.js +0 -1450
  718. package/dist/analysis/trend_detection/dynamic_weight_chart_generator.js.map +0 -1
  719. package/dist/analysis/trend_detection/kalman_chart_generator.d.ts +0 -6
  720. package/dist/analysis/trend_detection/kalman_chart_generator.d.ts.map +0 -1
  721. package/dist/analysis/trend_detection/kalman_chart_generator.js +0 -408
  722. package/dist/analysis/trend_detection/kalman_chart_generator.js.map +0 -1
  723. package/dist/analysis/trend_detection/regime_chart_generator.d.ts +0 -6
  724. package/dist/analysis/trend_detection/regime_chart_generator.d.ts.map +0 -1
  725. package/dist/analysis/trend_detection/regime_chart_generator.js +0 -345
  726. package/dist/analysis/trend_detection/regime_chart_generator.js.map +0 -1
  727. package/dist/analysis/trend_detection/tests/test_kalman_trend.d.ts +0 -2
  728. package/dist/analysis/trend_detection/tests/test_kalman_trend.d.ts.map +0 -1
  729. package/dist/analysis/trend_detection/tests/test_kalman_trend.js +0 -130
  730. package/dist/analysis/trend_detection/tests/test_kalman_trend.js.map +0 -1
  731. package/dist/analysis/trend_detection/tests/test_kalman_velocity_smoothing.d.ts +0 -2
  732. package/dist/analysis/trend_detection/tests/test_kalman_velocity_smoothing.d.ts.map +0 -1
  733. package/dist/analysis/trend_detection/tests/test_kalman_velocity_smoothing.js +0 -38
  734. package/dist/analysis/trend_detection/tests/test_kalman_velocity_smoothing.js.map +0 -1
  735. package/dist/analysis/trend_detection/volatility_chart_generator.d.ts +0 -6
  736. package/dist/analysis/trend_detection/volatility_chart_generator.d.ts.map +0 -1
  737. package/dist/analysis/trend_detection/volatility_chart_generator.js +0 -732
  738. package/dist/analysis/trend_detection/volatility_chart_generator.js.map +0 -1
@@ -0,0 +1,1836 @@
1
+ "use strict";
2
+ /**
3
+ * modules/dexbot_cow_runtime.ts - COW (Copy-on-Write) Batch Execution Runtime
4
+ *
5
+ * Handles on-chain order execution with Copy-on-Write working grid semantics,
6
+ * broadcast uncertainty recovery, and result processing.
7
+ *
8
+ * Each function takes the DEXBot instance as its first parameter, following
9
+ * the same pattern as dexbot_fill_runtime.ts.
10
+ */
11
+ const chainOrders = require('./chain_orders');
12
+ const { BroadcastUncertainError } = require('./dexbot_credential_client');
13
+ const { buildCreateOrderArgs, buildCreateOpFingerprint, extractBatchOperationResults, formatUnmatchedChainOrder, convertToSpreadPlaceholder, buildOutsideInPairGroups, isOrderPlaced, } = require('./order/utils/order');
14
+ const { validateCreateTargetSlots } = require('./order/utils/validate');
15
+ const { validateOrderSize, findPriceCollision } = require('./order/utils/math');
16
+ // Lazy accessor so test mocks on the math module export take effect at call time.
17
+ function getAssetFees(...args) { return require('./order/utils/math').getAssetFees(...args); }
18
+ const { COW_ACTIONS, ORDER_STATES, ORDER_TYPES, REBALANCE_STATES, } = require('./constants');
19
+ const Format = require('./order/format');
20
+ const { WorkingGrid } = require('./order/working_grid');
21
+ const { getErrorMessage } = require('./utils/errors');
22
+ /**
23
+ * Group orders into outside-in pairs for atomic create execution.
24
+ * @param {Array} orders
25
+ * @returns {Array<Array>}
26
+ */
27
+ function buildOutsideInPairGroupsForOrders(orders) {
28
+ return buildOutsideInPairGroups(orders, {
29
+ isValid: Boolean,
30
+ getType: (o) => o.type,
31
+ getPrice: (o) => o.price,
32
+ });
33
+ }
34
+ /**
35
+ * Build outside-in pair groups for create entry contexts.
36
+ * @param {Array} createEntries
37
+ * @returns {Array<Array>}
38
+ */
39
+ function buildOutsideInPairGroupsForCreateEntries(createEntries) {
40
+ return buildOutsideInPairGroups(createEntries, {
41
+ isValid: (e) => Boolean(e?.context?.order),
42
+ getType: (e) => e.context.order.type,
43
+ getPrice: (e) => e.context.order.price,
44
+ });
45
+ }
46
+ /**
47
+ * Extract operation results from a batch transaction result.
48
+ * @param {Object|Array|null} result
49
+ * @param {string} [warnContext='']
50
+ * @param {Function} [logFn] - Optional logger function, called with (msg, level) on unrecognized shape
51
+ * @returns {Array}
52
+ */
53
+ function extractOperationResults(result, warnContext = '', logFn = null) {
54
+ const extracted = extractBatchOperationResults(result);
55
+ if (Array.isArray(extracted))
56
+ return extracted;
57
+ if (result && logFn) {
58
+ const resultType = Array.isArray(result) ? 'array' : typeof result;
59
+ const keySummary = (resultType === 'object' && !Array.isArray(result))
60
+ ? Object.keys(result).slice(0, 8).join(',')
61
+ : '';
62
+ const contextSuffix = warnContext ? ` (${warnContext})` : '';
63
+ const keysSuffix = keySummary ? `; keys=[${keySummary}]` : '';
64
+ logFn(`[COW] Unrecognized operation_results shape${contextSuffix}; defaulting to empty results. resultType=${resultType}${keysSuffix}`, 'warn');
65
+ }
66
+ return [];
67
+ }
68
+ /**
69
+ * Find CREATE operation contexts whose broadcast result did not include a chain order id.
70
+ * @param {Array} operationResults
71
+ * @param {Array} opContexts
72
+ * @returns {Array<{index:number, ctx:Object}>}
73
+ */
74
+ function findMissingCreateResultContexts(operationResults, opContexts) {
75
+ const missing = [];
76
+ if (!Array.isArray(opContexts))
77
+ return missing;
78
+ for (let i = 0; i < opContexts.length; i++) {
79
+ const ctx = opContexts[i];
80
+ if (ctx?.kind !== 'create')
81
+ continue;
82
+ const chainOrderId = operationResults?.[i]?.[1];
83
+ if (!chainOrderId || !/^1\.7\.\d+$/.test(String(chainOrderId))) {
84
+ missing.push({ index: i, ctx });
85
+ }
86
+ }
87
+ return missing;
88
+ }
89
+ /**
90
+ * Run an immediate chain sync after a successful CREATE broadcast returned incomplete ids.
91
+ * @param {import('./dexbot_class').DEXBot} bot
92
+ * @param {string} [reason]
93
+ * @returns {Promise<void>}
94
+ */
95
+ async function recoverAfterMissingCreateResults(bot, reason = 'missing create operation results') {
96
+ try {
97
+ const accountRef = bot.accountId || bot.account?.id || bot.account;
98
+ if (!accountRef || !bot.manager || !chainOrders?.readOpenOrders) {
99
+ bot.manager?.logger?.log?.(`[COW] Recovery sync unavailable after ${reason}`, 'warn');
100
+ return;
101
+ }
102
+ const preRecoveryMissingCreateBlockers = Array.isArray(bot.manager._lastUnmatchedChainOrders)
103
+ ? bot.manager._lastUnmatchedChainOrders
104
+ .filter((order) => order?.reason === 'missing-create-result')
105
+ .map((order) => ({ ...order }))
106
+ : [];
107
+ const openOrders = await chainOrders.readOpenOrders(accountRef);
108
+ const recoveryResult = await bot.manager.syncFromOpenOrders(openOrders, {
109
+ skipAccounting: false,
110
+ });
111
+ preserveMissingCreateBlockersAfterRecovery(bot, preRecoveryMissingCreateBlockers, recoveryResult);
112
+ if (typeof bot.manager.persistGrid === 'function') {
113
+ await bot.manager.persistGrid();
114
+ }
115
+ }
116
+ catch (err) {
117
+ bot.manager?.logger?.log?.(`[COW] CRITICAL: Recovery sync failed after ${reason}: ${getErrorMessage(err)}`, 'error');
118
+ if (typeof bot.manager?.requestStructuralGridResync === 'function') {
119
+ try {
120
+ await bot.manager.requestStructuralGridResync(`recovery sync failed after ${reason}`, {
121
+ error: getErrorMessage(err)
122
+ });
123
+ }
124
+ catch (scheduleErr) {
125
+ bot.manager?.logger?.log?.(`[COW] CRITICAL: Failed to schedule structural resync after recovery failure: ${getErrorMessage(scheduleErr)}`, 'error');
126
+ }
127
+ }
128
+ }
129
+ }
130
+ /**
131
+ * Restore unresolved missing-create blockers after recovery if sync did not adopt them.
132
+ * @param {import('./dexbot_class').DEXBot} bot
133
+ * @param {Array} blockers
134
+ * @param {Object} recoveryResult
135
+ */
136
+ function preserveMissingCreateBlockersAfterRecovery(bot, blockers, recoveryResult) {
137
+ if (!Array.isArray(blockers) || blockers.length === 0 || !bot.manager)
138
+ return;
139
+ const adoptedSlotIds = new Set((Array.isArray(recoveryResult?.updatedOrders) ? recoveryResult.updatedOrders : [])
140
+ .filter((order) => order?.id && order?.orderId)
141
+ .map((order) => order.id));
142
+ const unresolvedBlockers = blockers.filter((blocker) => !blocker.slotId || !adoptedSlotIds.has(blocker.slotId));
143
+ if (unresolvedBlockers.length === 0)
144
+ return;
145
+ const currentUnmatched = Array.isArray(bot.manager._lastUnmatchedChainOrders)
146
+ ? bot.manager._lastUnmatchedChainOrders
147
+ : [];
148
+ const currentKeys = new Set(currentUnmatched.map((order) => `${order.reason || ''}:${order.slotId || ''}:${order.operationIndex ?? ''}`));
149
+ const restored = [...currentUnmatched];
150
+ for (const blocker of unresolvedBlockers) {
151
+ const key = `${blocker.reason || ''}:${blocker.slotId || ''}:${blocker.operationIndex ?? ''}`;
152
+ if (!currentKeys.has(key))
153
+ restored.push({ ...blocker });
154
+ }
155
+ if (restored.length !== currentUnmatched.length) {
156
+ bot.manager._lastUnmatchedChainOrders = restored;
157
+ bot.manager._lastUnmatchedChainOrdersAt = Date.now();
158
+ bot.manager.logger?.log?.(`[COW] Preserving ${restored.length - currentUnmatched.length} missing-create blocker(s) after recovery sync; ` +
159
+ `chain snapshot did not account for the affected slot(s).`, 'warn');
160
+ }
161
+ }
162
+ /**
163
+ * Merge missing CREATE result contexts into manager._lastUnmatchedChainOrders.
164
+ * @param {import('./dexbot_class').DEXBot} bot
165
+ * @param {Array<{index:number, ctx:Object}>} missingCreateResults
166
+ */
167
+ function markMissingCreateResultsAsStructuralBlocker(bot, missingCreateResults) {
168
+ const blockers = Array.isArray(missingCreateResults)
169
+ ? missingCreateResults.map((item) => {
170
+ const order = item.ctx?.order || {};
171
+ const fingerprint = [
172
+ `type=${order.type || 'unknown'}`,
173
+ `price=${Format.formatPrice6(order.price)}`,
174
+ `size=${Format.formatAmount(order.size)}`
175
+ ].join(',');
176
+ return {
177
+ chainOrderId: 'unknown',
178
+ type: order.type || null,
179
+ price: order.price,
180
+ size: order.size,
181
+ slotId: order.id || item.ctx?.id || null,
182
+ reason: 'missing-create-result',
183
+ operationIndex: item.index,
184
+ fingerprint,
185
+ };
186
+ })
187
+ : [];
188
+ if (bot.manager && blockers.length > 0) {
189
+ const existing = Array.isArray(bot.manager._lastUnmatchedChainOrders)
190
+ ? bot.manager._lastUnmatchedChainOrders
191
+ : [];
192
+ const keys = new Set(existing.map((order) => `${order.reason || ''}:${order.slotId || ''}:${order.operationIndex ?? ''}`));
193
+ const merged = [...existing];
194
+ for (const blocker of blockers) {
195
+ const key = `${blocker.reason || ''}:${blocker.slotId || ''}:${blocker.operationIndex ?? ''}`;
196
+ if (!keys.has(key)) {
197
+ merged.push(blocker);
198
+ keys.add(key);
199
+ }
200
+ }
201
+ bot.manager._lastUnmatchedChainOrders = merged;
202
+ bot.manager._lastUnmatchedChainOrdersAt = Date.now();
203
+ }
204
+ }
205
+ /**
206
+ * Format an unmatched chain order for COW logs.
207
+ * @param {Object} order
208
+ * @returns {string}
209
+ */
210
+ function formatUnmatchedChainOrderForLog(order) {
211
+ return formatUnmatchedChainOrder(order);
212
+ }
213
+ /**
214
+ * Record a pending CREATE broadcast on the manager.
215
+ * @param {import('./dexbot_class').DEXBot} bot
216
+ * @param {Object} entry
217
+ */
218
+ function recordPendingBroadcast(bot, entry) {
219
+ if (!bot.manager || !entry || !entry.order)
220
+ return;
221
+ if (!bot.manager._pendingBroadcasts || !(bot.manager._pendingBroadcasts instanceof Map)) {
222
+ bot.manager._pendingBroadcasts = new Map();
223
+ }
224
+ const fingerprint = buildCreateOpFingerprint({
225
+ side: entry.order.type,
226
+ assetA: bot.manager?.assets?.assetA?.id,
227
+ assetB: bot.manager?.assets?.assetB?.id,
228
+ sellInt: entry.finalInts?.sell,
229
+ receiveInt: entry.finalInts?.receive,
230
+ slotId: entry.order.id
231
+ });
232
+ if (!fingerprint) {
233
+ bot.manager.logger.log?.(`[COW] Skipped pending-broadcast record: could not build fingerprint for ${entry.order?.id || 'unknown'}`, 'warn');
234
+ return;
235
+ }
236
+ bot.manager._pendingBroadcasts.set(fingerprint, {
237
+ fingerprint,
238
+ opIndex: entry.opIndex,
239
+ ctxIndex: entry.ctxIndex,
240
+ slotId: entry.order.id,
241
+ orderId: entry.order.id,
242
+ orderType: entry.order.type,
243
+ order: entry.order,
244
+ finalInts: entry.finalInts,
245
+ batchId: bot._currentBatchId || null,
246
+ recordedAt: Date.now()
247
+ });
248
+ }
249
+ /**
250
+ * Clear the pending-broadcast cache.
251
+ * @param {Map} pendingBroadcasts
252
+ */
253
+ function clearPendingBroadcasts(pendingBroadcasts) {
254
+ if (pendingBroadcasts instanceof Map) {
255
+ pendingBroadcasts.clear();
256
+ }
257
+ }
258
+ /**
259
+ * Build a fingerprint for an on-chain order so it can be matched against
260
+ * the pending-broadcast cache.
261
+ * @param {import('./dexbot_class').DEXBot} bot
262
+ * @param {Object} chainOrder
263
+ * @param {string} slotId
264
+ * @returns {string|null}
265
+ */
266
+ function buildChainOrderFingerprint(bot, chainOrder, slotId) {
267
+ if (!chainOrder || !slotId)
268
+ return null;
269
+ const normalized = normalizeChainOrderForPendingMatch(bot, chainOrder);
270
+ if (!normalized)
271
+ return null;
272
+ return buildCreateOpFingerprint({
273
+ side: normalized.side,
274
+ assetA: normalized.assetA,
275
+ assetB: normalized.assetB,
276
+ sellInt: normalized.sellInt,
277
+ receiveInt: normalized.receiveInt,
278
+ slotId
279
+ });
280
+ }
281
+ /**
282
+ * Normalize raw BitShares limit_order_object data into the integer tuple
283
+ * used by pending-broadcast recovery.
284
+ * @param {import('./dexbot_class').DEXBot} bot
285
+ * @param {Object} chainOrder
286
+ * @returns {{side: string, assetA: string, assetB: string, sellInt: number, receiveInt: number}|null}
287
+ */
288
+ function normalizeChainOrderForPendingMatch(bot, chainOrder) {
289
+ if (!chainOrder)
290
+ return null;
291
+ const assetA = bot.manager?.assets?.assetA?.id;
292
+ const assetB = bot.manager?.assets?.assetB?.id;
293
+ if (!assetA || !assetB)
294
+ return null;
295
+ const explicitSide = (chainOrder.type === 'buy' || chainOrder.type === 'sell')
296
+ ? chainOrder.type
297
+ : null;
298
+ const explicitSell = chainOrder.sellInt ?? chainOrder.sell;
299
+ const explicitReceive = chainOrder.receiveInt ?? chainOrder.receive;
300
+ if (explicitSide && Number.isFinite(Number(explicitSell)) && Number.isFinite(Number(explicitReceive))) {
301
+ return {
302
+ side: explicitSide,
303
+ assetA,
304
+ assetB,
305
+ sellInt: Number(explicitSell),
306
+ receiveInt: Number(explicitReceive)
307
+ };
308
+ }
309
+ const base = chainOrder.sell_price?.base;
310
+ const quote = chainOrder.sell_price?.quote;
311
+ if (!base || !quote || !base.asset_id || !quote.asset_id)
312
+ return null;
313
+ const baseAmount = Number(base.amount);
314
+ const quoteAmount = Number(quote.amount);
315
+ if (!Number.isFinite(baseAmount) || !Number.isFinite(quoteAmount))
316
+ return null;
317
+ if (base.asset_id === assetA && quote.asset_id === assetB) {
318
+ return { side: 'sell', assetA, assetB, sellInt: baseAmount, receiveInt: quoteAmount };
319
+ }
320
+ if (base.asset_id === assetB && quote.asset_id === assetA) {
321
+ return { side: 'buy', assetA, assetB, sellInt: baseAmount, receiveInt: quoteAmount };
322
+ }
323
+ return null;
324
+ }
325
+ /**
326
+ * Find a chain order that matches a planned slot using price+size proximity.
327
+ * @param {import('./dexbot_class').DEXBot} bot
328
+ * @param {Array} chainOrders - Open chain orders for the account
329
+ * @param {string} slotId - Planned grid slot id
330
+ * @param {Object} planned - { sell, receive, orderType } integers from the planned op
331
+ * @returns {Object|null} Matching chain order, or null
332
+ */
333
+ function findChainOrderForSlot(bot, chainOrders, slotId, planned) {
334
+ if (!Array.isArray(chainOrders) || !slotId)
335
+ return null;
336
+ const assetA = bot.manager?.assets?.assetA?.id;
337
+ const assetB = bot.manager?.assets?.assetB?.id;
338
+ if (!assetA || !assetB)
339
+ return null;
340
+ // 1. Exact fingerprint match.
341
+ for (const o of chainOrders) {
342
+ const fp = buildChainOrderFingerprint(bot, o, slotId);
343
+ if (fp && bot.manager._pendingBroadcasts?.has(fp)) {
344
+ return o;
345
+ }
346
+ }
347
+ if (!planned || !Number.isFinite(Number(planned.sell)) || !Number.isFinite(Number(planned.receive))) {
348
+ return null;
349
+ }
350
+ // 2. Near match: same side, sell int within 1, receive int within 1% or 2 units.
351
+ const targetSell = Number(planned.sell);
352
+ const targetReceive = Number(planned.receive);
353
+ const plannedSide = planned.orderType ||
354
+ planned.side ||
355
+ bot.manager._pendingBroadcasts?.get?.(planned.fingerprint)?.orderType ||
356
+ bot.manager.orders.get(slotId)?.type;
357
+ if (plannedSide !== 'buy' && plannedSide !== 'sell') {
358
+ return null;
359
+ }
360
+ let best = null;
361
+ let bestDistance = Infinity;
362
+ for (const o of chainOrders) {
363
+ const normalized = normalizeChainOrderForPendingMatch(bot, o);
364
+ if (!normalized)
365
+ continue;
366
+ if (normalized.side !== plannedSide)
367
+ continue;
368
+ const sell = Number(normalized.sellInt);
369
+ const receive = Number(normalized.receiveInt);
370
+ if (!Number.isFinite(sell) || !Number.isFinite(receive))
371
+ continue;
372
+ const sellDelta = Math.abs(sell - targetSell);
373
+ const receiveDelta = Math.abs(receive - targetReceive);
374
+ const receiveTol = Math.max(2, Math.floor(targetReceive * 0.01));
375
+ if (sellDelta > 1 || receiveDelta > receiveTol)
376
+ continue;
377
+ const distance = sellDelta * 1000 + receiveDelta;
378
+ if (distance < bestDistance) {
379
+ best = o;
380
+ bestDistance = distance;
381
+ }
382
+ }
383
+ return best;
384
+ }
385
+ /**
386
+ * Reconcile a broadcast whose chain state is unknown.
387
+ * Thin wrapper that optionally acquires _fillProcessingLock before delegating.
388
+ * @param {import('./dexbot_class').DEXBot} bot
389
+ * @param {BroadcastUncertainError} err
390
+ * @param {Array<Object>} opContexts
391
+ * @param {Object} [options]
392
+ * @returns {Promise<Object>}
393
+ */
394
+ async function reconcileAfterUncertainBroadcast(bot, err, opContexts, options = {}) {
395
+ if (bot.manager?._fillProcessingLock &&
396
+ typeof bot.manager._fillProcessingLock.acquire === 'function' &&
397
+ !bot.manager._fillProcessingLock.isReentrant()) {
398
+ return bot.manager._fillProcessingLock.acquire(() => reconcileAfterUncertainBroadcast(bot, err, opContexts, options));
399
+ }
400
+ return reconcileAfterUncertainBroadcastImpl(bot, err, opContexts, options);
401
+ }
402
+ /**
403
+ * Reconcile a broadcast whose chain state is unknown (implementation).
404
+ * @param {import('./dexbot_class').DEXBot} bot
405
+ * @param {BroadcastUncertainError} err
406
+ * @param {Array<Object>} opContexts
407
+ * @param {Object} options
408
+ * @returns {Promise<Object>}
409
+ */
410
+ async function reconcileAfterUncertainBroadcastImpl(bot, err, opContexts, _options) {
411
+ const startedAt = Date.now();
412
+ const pending = (bot.manager && bot.manager._pendingBroadcasts instanceof Map)
413
+ ? Array.from(bot.manager._pendingBroadcasts.values())
414
+ : [];
415
+ const createContextCount = opContexts.filter((c) => c && c.kind === 'create').length;
416
+ const nonCreateContextCount = opContexts.length - createContextCount;
417
+ bot.manager.logger.log(`[COW][UNCERTAIN] batchId=${err?.batchId || 'n/a'} ops=${opContexts.length} ` +
418
+ `creates=${createContextCount} nonCreates=${nonCreateContextCount} ` +
419
+ `staleSinceMs=${err?.timeoutMs || 'n/a'}. Entering reconcile-then-decide.`, 'warn');
420
+ if (!chainOrders?.readOpenOrders) {
421
+ bot.manager.logger.log('[COW][UNCERTAIN] readOpenOrders unavailable; falling back to structural resync only.', 'error');
422
+ if (typeof bot.manager.requestStructuralGridResync === 'function') {
423
+ await bot.manager.requestStructuralGridResync('broadcast uncertain — readOpenOrders unavailable', { batchId: err?.batchId || null });
424
+ }
425
+ clearPendingBroadcasts(bot.manager?._pendingBroadcasts);
426
+ return { executed: false, hadRotation: false, uncertain: true };
427
+ }
428
+ // 1. Read the chain
429
+ const accountRef = bot.accountId || bot.account?.id || bot.account;
430
+ let chainSnapshot = [];
431
+ try {
432
+ chainSnapshot = await chainOrders.readOpenOrders(accountRef);
433
+ }
434
+ catch (readErr) {
435
+ bot.manager.logger.log(`[COW][UNCERTAIN] readOpenOrders failed: ${readErr?.message || readErr}. ` +
436
+ `Falling back to structural resync.`, 'error');
437
+ if (typeof bot.manager.requestStructuralGridResync === 'function') {
438
+ await bot.manager.requestStructuralGridResync('broadcast uncertain — readOpenOrders failed', { batchId: err?.batchId || null, error: readErr?.message || String(readErr) });
439
+ }
440
+ clearPendingBroadcasts(bot.manager?._pendingBroadcasts);
441
+ return { executed: false, hadRotation: false, uncertain: true };
442
+ }
443
+ const adopted = [];
444
+ let discarded = [];
445
+ // 2. For each pending broadcast, look for a chain match.
446
+ for (const entry of pending) {
447
+ const match = findChainOrderForSlot(bot, chainSnapshot, entry.slotId, {
448
+ sell: entry.finalInts?.sell,
449
+ receive: entry.finalInts?.receive,
450
+ orderType: entry.orderType,
451
+ fingerprint: entry.fingerprint,
452
+ });
453
+ if (match) {
454
+ adopted.push({ entry, match });
455
+ }
456
+ else {
457
+ discarded.push(entry);
458
+ }
459
+ }
460
+ // 2b. Second pass: search for any unmatched chain orders by fingerprint
461
+ // across all known pending slots.
462
+ if (adopted.length < pending.length) {
463
+ const adoptedSlotIds = new Set(adopted.map((a) => a.entry.slotId));
464
+ for (const o of chainSnapshot) {
465
+ if (adopted.some((a) => a.match.id === o.id))
466
+ continue;
467
+ for (const entry of pending) {
468
+ if (adoptedSlotIds.has(entry.slotId))
469
+ continue;
470
+ const fp = buildChainOrderFingerprint(bot, o, entry.slotId);
471
+ if (fp && bot.manager._pendingBroadcasts?.has(fp)) {
472
+ adopted.push({ entry, match: o });
473
+ adoptedSlotIds.add(entry.slotId);
474
+ break;
475
+ }
476
+ }
477
+ }
478
+ // Rebuild discarded list to remove newly adopted entries.
479
+ const newlyAdoptedSlotIds = new Set(adopted.map((a) => a.entry.slotId));
480
+ discarded = pending.filter((e) => !newlyAdoptedSlotIds.has(e.slotId));
481
+ }
482
+ // 3a. Re-read chain for discarded CREATE entries to catch broadcasts that
483
+ // landed between the initial read and this point (TOCTOU window).
484
+ if (discarded.length > 0 && typeof chainOrders.readOpenOrders === 'function') {
485
+ const createDiscarded = discarded.filter((e) => {
486
+ const ctx = opContexts[e.ctxIndex];
487
+ return ctx && ctx.kind === 'create';
488
+ });
489
+ if (createDiscarded.length > 0) {
490
+ try {
491
+ const freshChain = await chainOrders.readOpenOrders(accountRef);
492
+ const remainingDiscarded = [];
493
+ for (const entry of discarded) {
494
+ const ctx = opContexts[entry.ctxIndex];
495
+ if (ctx && ctx.kind === 'create') {
496
+ const match = findChainOrderForSlot(bot, freshChain, entry.slotId, {
497
+ sell: entry.finalInts?.sell,
498
+ receive: entry.finalInts?.receive,
499
+ orderType: entry.orderType,
500
+ fingerprint: entry.fingerprint,
501
+ });
502
+ if (match) {
503
+ adopted.push({ entry, match });
504
+ bot.manager.logger.log(`[COW][UNCERTAIN] Late-adopted discarded CREATE for slot ${entry.slotId} (${match.id}) via fresh chain read`, 'info');
505
+ }
506
+ else {
507
+ remainingDiscarded.push(entry);
508
+ }
509
+ }
510
+ else {
511
+ remainingDiscarded.push(entry);
512
+ }
513
+ }
514
+ discarded = remainingDiscarded;
515
+ }
516
+ catch {
517
+ bot.manager.logger.log('[COW][UNCERTAIN] Fresh chain read for late adoption failed; proceeding with original discard decisions.', 'warn');
518
+ }
519
+ }
520
+ }
521
+ // 3b. Apply decisions
522
+ let adoptedCount = 0;
523
+ let discardedCount = 0;
524
+ for (const { entry, match } of adopted) {
525
+ adoptedCount++;
526
+ const plannedOpCtx = opContexts[entry.ctxIndex];
527
+ if (plannedOpCtx && plannedOpCtx.kind === 'create') {
528
+ const chainOrderId = match.id;
529
+ const expectedType = plannedOpCtx.order?.type || entry.orderType;
530
+ try {
531
+ const btsFeeData = getAssetFees('BTS');
532
+ await bot.manager.synchronizeWithChain({
533
+ gridOrderId: plannedOpCtx.order?.id || entry.slotId,
534
+ chainOrderId,
535
+ expectedType,
536
+ fee: btsFeeData.createFee,
537
+ }, 'createOrder');
538
+ }
539
+ catch (syncErr) {
540
+ bot.manager.logger.log(`[COW][UNCERTAIN] Failed to adopt matched order ${chainOrderId} for slot ${entry.slotId}: ${syncErr?.message || syncErr}`, 'error');
541
+ }
542
+ }
543
+ // Remove from pending broadcasts — matched entries are resolved.
544
+ if (entry.fingerprint && bot.manager._pendingBroadcasts?.has(entry.fingerprint)) {
545
+ bot.manager._pendingBroadcasts.delete(entry.fingerprint);
546
+ }
547
+ }
548
+ for (const entry of discarded) {
549
+ discardedCount++;
550
+ const plannedOpCtx = opContexts[entry.ctxIndex];
551
+ if (plannedOpCtx && plannedOpCtx.kind === 'create') {
552
+ try {
553
+ // Restore target grid sizes for discarded CREATEs so the slots are
554
+ // immediately available for the next cycle without waiting for a
555
+ // structural resync. entry.order is the pending-broadcast target
556
+ // order (captured at broadcast time, before the working grid was
557
+ // committed or discarded).
558
+ if (entry.order?.id && entry.order?.size && entry.order?.type) {
559
+ const slot = bot.manager.orders.get(entry.order.id);
560
+ if (slot) {
561
+ bot.manager.logger.log(`[COW][UNCERTAIN] Restored target size for discarded CREATE slot ${entry.slotId} (size: ${entry.order.size})`, 'debug');
562
+ const updates = [{
563
+ ...slot,
564
+ size: entry.order.size,
565
+ price: entry.order.price,
566
+ }];
567
+ if (typeof bot.manager.applyGridUpdateBatch === 'function') {
568
+ await bot.manager.applyGridUpdateBatch(updates, 'uncertain-broadcast-discard-restore');
569
+ }
570
+ }
571
+ }
572
+ }
573
+ catch (restoreErr) {
574
+ bot.manager.logger.log(`[COW][UNCERTAIN] Failed to restore slot ${entry.slotId} after discard: ${restoreErr?.message || restoreErr}`, 'error');
575
+ }
576
+ }
577
+ // Remove from pending broadcasts.
578
+ if (entry.fingerprint && bot.manager._pendingBroadcasts?.has(entry.fingerprint)) {
579
+ bot.manager._pendingBroadcasts.delete(entry.fingerprint);
580
+ }
581
+ }
582
+ // 4. If some entries remain unresolved (broadcasts that point to opContext
583
+ // indices beyond the array — shouldn't happen, but guard defensively),
584
+ // treat them as discarded.
585
+ const remainingAfterDecide = bot.manager._pendingBroadcasts instanceof Map
586
+ ? bot.manager._pendingBroadcasts.size
587
+ : 0;
588
+ if (remainingAfterDecide > 0) {
589
+ const remainingEntries = Array.from(bot.manager._pendingBroadcasts.values());
590
+ for (const entry of remainingEntries) {
591
+ discardedCount++;
592
+ bot.manager.logger.log(`[COW][UNCERTAIN] Cleaning residual pending broadcast for slot ${entry.slotId} (opIndex=${entry.opIndex})`, 'debug');
593
+ }
594
+ bot.manager._pendingBroadcasts.clear();
595
+ }
596
+ // 5. Log structured summary
597
+ const elapsed = Date.now() - startedAt;
598
+ bot.manager.logger.log(`[COW][UNCERTAIN] Reconciled: ${adoptedCount} adopted, ${discardedCount} discarded ` +
599
+ `(opContexts=${opContexts.length}, pending=${pending.length}, ` +
600
+ `chainOrders=${chainSnapshot.length}) in ${elapsed}ms.`, 'info');
601
+ // 6. Persist master grid changes from the reconciliation.
602
+ if (adoptedCount > 0 || discardedCount > 0) {
603
+ if (typeof bot.manager.persistGrid === 'function') {
604
+ try {
605
+ await bot.manager.persistGrid();
606
+ }
607
+ catch (persistErr) {
608
+ bot.manager.logger.log(`[COW][UNCERTAIN] Persist after reconcile failed: ${persistErr?.message || persistErr}`, 'error');
609
+ }
610
+ }
611
+ }
612
+ // 7. Request structural resync if any chain orders remain unaccounted for
613
+ // after the reconciliation, ensuring the next cycle re-plans from a clean
614
+ // chain snapshot.
615
+ const alreadyScheduled = bot._structuralGridResyncRunning || bot._structuralGridResyncTimer;
616
+ if (!alreadyScheduled && chainSnapshot.length > 0) {
617
+ const reconciledOrderIds = new Set(adopted.map((a) => a.match?.id).filter(Boolean));
618
+ const unreconciledCount = chainSnapshot.filter((o) => !reconciledOrderIds.has(o.id)).length;
619
+ if (unreconciledCount > 0) {
620
+ bot.manager.logger.log(`[COW][UNCERTAIN] ${unreconciledCount} chain order(s) remain unreconciled after uncertain broadcast recovery. ` +
621
+ `These may be legitimate pre-existing orders or leftovers from a prior cycle. Requesting structural resync.`, 'warn');
622
+ if (typeof bot.manager.requestStructuralGridResync === 'function') {
623
+ await bot.manager.requestStructuralGridResync('unreconciled orders after uncertain broadcast', {
624
+ batchId: err?.batchId || null,
625
+ pendingCount: pending.length,
626
+ adoptedCount,
627
+ discardedCount,
628
+ unreconciledCount
629
+ });
630
+ }
631
+ else {
632
+ bot._warn?.('[COW][UNCERTAIN] requestStructuralGridResync unavailable; cannot schedule structural resync.');
633
+ }
634
+ }
635
+ }
636
+ return { executed: false, hadRotation: false, uncertain: true, adoptedCount, discardedCount };
637
+ }
638
+ /**
639
+ * Auto-cancel one unmatched orphan (price-drift orphan) per cycle.
640
+ * @param {import('./dexbot_class').DEXBot} bot
641
+ * @returns {Promise<{cancelled: boolean, reason?: string, orderId?: string}>}
642
+ */
643
+ async function autoCancelOneUnmatchedOrphan(bot) {
644
+ const cycleId = bot._currentCycleId || 0;
645
+ const recoveryActive = bot.manager?._recoveryState?.structuralResyncRequested === true;
646
+ const cycleCap = recoveryActive ? 5 : 1;
647
+ if (bot._autoCancelOrphanCycleMarker === cycleId) {
648
+ if (bot._autoCancelOrphanSubCount >= cycleCap) {
649
+ return { cancelled: false, reason: 'cap-reached-this-cycle', subCount: bot._autoCancelOrphanSubCount };
650
+ }
651
+ }
652
+ else {
653
+ bot._autoCancelOrphanCycleMarker = cycleId;
654
+ bot._autoCancelOrphanSubCount = 0;
655
+ }
656
+ const pending = (bot.manager && bot.manager._pendingBroadcasts instanceof Map)
657
+ ? bot.manager._pendingBroadcasts.size
658
+ : 0;
659
+ if (pending > 0) {
660
+ return { cancelled: false, reason: 'pending-broadcasts-active' };
661
+ }
662
+ const unmatched = Array.isArray(bot.manager?._lastUnmatchedChainOrders)
663
+ ? bot.manager._lastUnmatchedChainOrders
664
+ : [];
665
+ if (unmatched.length === 0) {
666
+ return { cancelled: false, reason: 'no-unmatched' };
667
+ }
668
+ const fingerprinted = unmatched.find((u) => u && u.fingerprint);
669
+ if (fingerprinted) {
670
+ return { cancelled: false, reason: 'fingerprinted-handle-via-recovery' };
671
+ }
672
+ const target = unmatched.find((u) => u && u.reason === 'price-drift-orphan');
673
+ if (!target) {
674
+ return { cancelled: false, reason: 'no-price-drift-orphan', message: 'no price-drift orphan to cancel; other unmatched orders are adoptable' };
675
+ }
676
+ const orderId = target.id || target.orderId || target.chainOrderId;
677
+ if (!orderId) {
678
+ return { cancelled: false, reason: 'no-orderId' };
679
+ }
680
+ if (!chainOrders?.cancelOrder) {
681
+ return { cancelled: false, reason: 'cancelOrder-unavailable' };
682
+ }
683
+ try {
684
+ await chainOrders.cancelOrder(bot.account, bot.privateKey, orderId);
685
+ if (typeof chainOrders.recordOwnCancel === 'function') {
686
+ chainOrders.recordOwnCancel(orderId);
687
+ }
688
+ bot._autoCancelOrphanSubCount++;
689
+ bot.manager.logger.log(`[COW] Auto-cancelled ${bot._autoCancelOrphanSubCount}/${unmatched.length} unmatched chain order ` +
690
+ `(${formatUnmatchedChainOrderForLog(target)}) — per-cycle cap=${cycleCap}.`, 'warn');
691
+ return { cancelled: true, orderId };
692
+ }
693
+ catch (err) {
694
+ bot.manager.logger.log(`[COW] Auto-cancel of unmatched chain order ${orderId} failed: ${err?.message || err}`, 'error');
695
+ return { cancelled: false, reason: 'cancel-failed', error: err?.message || String(err) };
696
+ }
697
+ }
698
+ /**
699
+ * Check whether to execute creates in outside-in pair mode.
700
+ * @param {import('./dexbot_class').DEXBot} bot
701
+ * @param {Array} opContexts
702
+ * @returns {boolean}
703
+ */
704
+ function shouldExecuteCreatePairMode(_bot, opContexts) {
705
+ if (!Array.isArray(opContexts) || opContexts.length < 2)
706
+ return false;
707
+ if (!opContexts.every((ctx) => ctx?.kind === 'create' && ctx?.order))
708
+ return false;
709
+ let hasBuy = false;
710
+ let hasSell = false;
711
+ for (const ctx of opContexts) {
712
+ if (ctx.order.type === ORDER_TYPES.BUY)
713
+ hasBuy = true;
714
+ if (ctx.order.type === ORDER_TYPES.SELL)
715
+ hasSell = true;
716
+ if (hasBuy && hasSell)
717
+ return true;
718
+ }
719
+ return false;
720
+ }
721
+ /**
722
+ * Execute operations with retry on BroadcastUncertainError.
723
+ * @param {import('./dexbot_class').DEXBot} bot
724
+ * @param {Array} operations
725
+ * @param {Array} opContexts
726
+ * @returns {Promise<{result: Object, opContexts: Array}>}
727
+ */
728
+ async function executeWithRetryOnUncertain(bot, operations, opContexts) {
729
+ const MAX_RETRIES = 1;
730
+ for (let attempt = 1;; attempt++) {
731
+ try {
732
+ return await executeOperationsWithStrategy(bot, operations, opContexts);
733
+ }
734
+ catch (err) {
735
+ const isRetriable = err instanceof BroadcastUncertainError
736
+ && !err.partialOnChainState
737
+ && attempt <= MAX_RETRIES;
738
+ if (isRetriable) {
739
+ bot.manager.logger.log(`[COW] Broadcast uncertain (attempt ${attempt}/${MAX_RETRIES + 1}), retrying...`, 'warn');
740
+ await bot._ensureCredentialDaemonWritable('COW batch retry');
741
+ try {
742
+ const accountRef = bot.accountId || bot.account?.id || bot.account;
743
+ const freshChain = await chainOrders.readOpenOrders(accountRef);
744
+ if (freshChain.length > 0 && bot.manager?.syncFromOpenOrders) {
745
+ await bot.manager.syncFromOpenOrders(freshChain, {
746
+ skipAccounting: true,
747
+ });
748
+ }
749
+ }
750
+ catch (syncErr) {
751
+ bot.manager.logger.log(`[COW] Pre-retry sync failed (non-fatal): ${syncErr?.message || syncErr}`, 'warn');
752
+ }
753
+ continue;
754
+ }
755
+ throw err;
756
+ }
757
+ }
758
+ }
759
+ /**
760
+ * Execute blockchain operations with appropriate strategy (single batch or pair mode).
761
+ * @param {import('./dexbot_class').DEXBot} bot
762
+ * @param {Array} operations
763
+ * @param {Array} opContexts
764
+ * @returns {Promise<{result: Object, opContexts: Array}>}
765
+ */
766
+ async function executeOperationsWithStrategy(bot, operations, opContexts) {
767
+ if (!shouldExecuteCreatePairMode(bot, opContexts)) {
768
+ const result = await chainOrders.executeBatch(bot.account, bot.privateKey, operations);
769
+ return { result, opContexts };
770
+ }
771
+ const createEntries = [];
772
+ for (let i = 0; i < operations.length; i++) {
773
+ createEntries.push({
774
+ operation: operations[i],
775
+ context: opContexts[i],
776
+ });
777
+ }
778
+ const groups = buildOutsideInPairGroupsForCreateEntries(createEntries);
779
+ const mergedOperationResults = [];
780
+ const mergedRawResults = [];
781
+ const mergedContexts = [];
782
+ for (let idx = 0; idx < groups.length; idx++) {
783
+ const group = groups[idx];
784
+ const groupOps = group.map((e) => e.operation);
785
+ const groupContexts = group.map((e) => e.context);
786
+ bot.manager.logger.log(`[COW] Broadcasting create pair group ${idx + 1}/${groups.length} (${groupOps.length} op${groupOps.length > 1 ? 's' : ''}, outside->center)`, 'info');
787
+ let groupResult;
788
+ try {
789
+ groupResult = await chainOrders.executeBatch(bot.account, bot.privateKey, groupOps);
790
+ }
791
+ catch (err) {
792
+ const groupsBroadcast = idx;
793
+ const groupsTotal = groups.length;
794
+ const broadcastedOperationCount = mergedContexts.length;
795
+ bot.manager.logger.log(`[COW] Grouped create execution failed at group ${idx + 1}/${groupsTotal}; ${groupsBroadcast} group(s) already broadcast (${broadcastedOperationCount} op context(s)). Partial on-chain state is possible.`, 'error');
796
+ err.partialOnChainState = groupsBroadcast > 0;
797
+ err.groupsBroadcast = groupsBroadcast;
798
+ err.groupsTotal = groupsTotal;
799
+ err.broadcastedOperationCount = broadcastedOperationCount;
800
+ throw err;
801
+ }
802
+ const groupOpResults = extractOperationResults(groupResult, '', bot.manager?.logger?.log?.bind(bot.manager?.logger));
803
+ mergedOperationResults.push(...groupOpResults);
804
+ mergedRawResults.push(groupResult?.raw || null);
805
+ mergedContexts.push(...groupContexts);
806
+ }
807
+ return {
808
+ result: {
809
+ success: true,
810
+ raw: {
811
+ grouped: true,
812
+ groupsExecuted: groups.length,
813
+ groupResults: mergedRawResults,
814
+ },
815
+ operation_results: mergedOperationResults,
816
+ grouped: true,
817
+ groupsExecuted: groups.length
818
+ },
819
+ opContexts: mergedContexts
820
+ };
821
+ }
822
+ /**
823
+ * Validate that operations can be executed with available funds before broadcasting.
824
+ * @param {import('./dexbot_class').DEXBot} bot
825
+ * @param {Array} operations
826
+ * @param {Object} assetA
827
+ * @param {Object} assetB
828
+ * @returns {Object} { isValid: boolean, summary: string }
829
+ */
830
+ function validateOperationFunds(bot, operations, assetA, assetB) {
831
+ if (!operations || operations.length === 0) {
832
+ return { isValid: true, summary: 'No operations to validate' };
833
+ }
834
+ const { blockchainToFloat, floatToBlockchainInt, quantizeFloat } = require('./order/utils/math');
835
+ let snap = bot.manager?.getChainFundsSnapshot?.();
836
+ if (!snap) {
837
+ snap = { chainFreeSell: 0, chainFreeBuy: 0 };
838
+ bot.manager?.logger?.log?.('[COW][VALIDATION] getChainFundsSnapshot unavailable — fund validation skipped (assuming no balance)', 'warn');
839
+ }
840
+ const netRequiredFunds = { [assetA.id]: 0, [assetB.id]: 0 };
841
+ const runningRequiredFunds = { [assetA.id]: 0, [assetB.id]: 0 };
842
+ const peakRequiredFunds = { [assetA.id]: 0, [assetB.id]: 0 };
843
+ for (const op of operations) {
844
+ if (!op?.op_data)
845
+ continue;
846
+ let sellAssetId = null;
847
+ let sellAmountInt = 0;
848
+ if (op.op_name === 'limit_order_create') {
849
+ sellAssetId = op.op_data.amount_to_sell?.asset_id;
850
+ sellAmountInt = op.op_data.amount_to_sell?.amount;
851
+ }
852
+ else if (op.op_name === 'limit_order_update') {
853
+ sellAssetId = op.op_data.new_price?.base?.asset_id;
854
+ sellAmountInt = op.op_data.new_price?.base?.amount;
855
+ }
856
+ if (sellAssetId && (sellAmountInt !== undefined && sellAmountInt !== null)) {
857
+ const precision = (sellAssetId === assetA.id) ? assetA.precision : assetB.precision;
858
+ const assetSymbol = (sellAssetId === assetA.id) ? assetA.symbol : assetB.symbol;
859
+ if (Number(sellAmountInt) <= 0) {
860
+ return {
861
+ isValid: false,
862
+ summary: `[VALIDATION] CRITICAL: Zero amount order detected for ${assetSymbol} (assetId=${sellAssetId})`,
863
+ violations: [{ asset: assetSymbol, sizeInt: sellAmountInt, reason: 'Zero amount' }]
864
+ };
865
+ }
866
+ let signedDelta = 0;
867
+ if (op.op_name === 'limit_order_update') {
868
+ const deltaAssetId = op.op_data.delta_amount_to_sell?.asset_id;
869
+ const deltaSellInt = op.op_data.delta_amount_to_sell?.amount;
870
+ if (deltaAssetId === sellAssetId && Number.isFinite(Number(deltaSellInt))) {
871
+ signedDelta = blockchainToFloat(deltaSellInt, precision);
872
+ }
873
+ }
874
+ else {
875
+ signedDelta = blockchainToFloat(sellAmountInt, precision);
876
+ }
877
+ netRequiredFunds[sellAssetId] = quantizeFloat((netRequiredFunds[sellAssetId] || 0) + signedDelta, precision);
878
+ runningRequiredFunds[sellAssetId] = quantizeFloat((runningRequiredFunds[sellAssetId] || 0) + signedDelta, precision);
879
+ const nextPeak = Math.max(Number(peakRequiredFunds[sellAssetId] || 0), Number(runningRequiredFunds[sellAssetId] || 0));
880
+ peakRequiredFunds[sellAssetId] = quantizeFloat(nextPeak, precision);
881
+ }
882
+ }
883
+ const availableFunds = {
884
+ [assetA.id]: quantizeFloat(snap.chainFreeSell || 0, assetA.precision),
885
+ [assetB.id]: quantizeFloat(snap.chainFreeBuy || 0, assetB.precision)
886
+ };
887
+ const fundViolations = [];
888
+ for (const assetId in peakRequiredFunds) {
889
+ const required = peakRequiredFunds[assetId];
890
+ const netRequired = netRequiredFunds[assetId] || 0;
891
+ const available = availableFunds[assetId] || 0;
892
+ const prec = (assetId === assetA.id) ? assetA.precision : assetB.precision;
893
+ if (floatToBlockchainInt(required, prec) > floatToBlockchainInt(available, prec)) {
894
+ fundViolations.push({
895
+ asset: assetId === assetA.id ? assetA.symbol : assetB.symbol,
896
+ required,
897
+ netRequired,
898
+ available,
899
+ deficit: quantizeFloat(required - available, prec)
900
+ });
901
+ }
902
+ }
903
+ if (fundViolations.length > 0) {
904
+ let summary = `[VALIDATION] Fund validation FAILED:\n`;
905
+ for (const v of fundViolations) {
906
+ summary += ` ${v.asset}: peakRequired=${Format.formatAmount8(v.required)}, netRequired=${Format.formatAmount8(v.netRequired)}, available=${Format.formatAmount8(v.available)}, deficit=${Format.formatAmount8(v.deficit)}\n`;
907
+ }
908
+ return { isValid: false, summary: summary.trim(), violations: fundViolations };
909
+ }
910
+ const summary = `[VALIDATION] PASSED: ${operations.length} operations`;
911
+ return { isValid: true, summary };
912
+ }
913
+ /**
914
+ * Resolve the ideal size from an order-like object with fallback.
915
+ * @param {import('./dexbot_class').DEXBot} bot
916
+ * @param {Object|null} orderLike
917
+ * @param {number|null} [fallbackSize=null]
918
+ * @returns {number|null}
919
+ */
920
+ function resolveIdealSizeForValidation(_bot, orderLike, fallbackSize = null) {
921
+ const candidates = [
922
+ orderLike?.idealSize,
923
+ orderLike?.order?.idealSize,
924
+ orderLike?.size,
925
+ orderLike?.order?.size,
926
+ fallbackSize
927
+ ];
928
+ for (const candidate of candidates) {
929
+ const numeric = Number(candidate);
930
+ if (Number.isFinite(numeric) && numeric > 0) {
931
+ return numeric;
932
+ }
933
+ }
934
+ return null;
935
+ }
936
+ /**
937
+ * Validate that an order size is safe to execute.
938
+ * @param {import('./dexbot_class').DEXBot} bot
939
+ * @param {number} size
940
+ * @param {string} type
941
+ * @param {Object|null} [orderLike=null]
942
+ * @param {number|null} [fallbackSize=null]
943
+ * @returns {import('./types').OrderValidationResult}
944
+ */
945
+ function validateOrderSizeForExecution(bot, size, type, orderLike = null, fallbackSize = null) {
946
+ return validateOrderSize(size, type, bot.manager.assets, bot.config.gridLimits?.MIN_ORDER_SIZE_FACTOR, resolveIdealSizeForValidation(bot, orderLike, fallbackSize), bot.config.gridLimits?.PARTIAL_DUST_THRESHOLD_PERCENTAGE);
947
+ }
948
+ /**
949
+ * Build COW actions array from a simple plan object.
950
+ * @param {import('./dexbot_class').DEXBot} bot
951
+ * @param {Object|Array} plan
952
+ * @returns {Array}
953
+ */
954
+ function buildActionsFromPlan(_bot, plan) {
955
+ const normalizedPlan = Array.isArray(plan)
956
+ ? { ordersToPlace: plan }
957
+ : (plan || {});
958
+ const { ordersToPlace = [], ordersToRotate = [], ordersToUpdate = [], ordersToCancel = [] } = normalizedPlan;
959
+ const actions = [];
960
+ for (const o of ordersToCancel) {
961
+ if (o?.orderId) {
962
+ actions.push({ type: COW_ACTIONS.CANCEL, id: o.id, orderId: o.orderId });
963
+ }
964
+ }
965
+ for (const r of ordersToRotate) {
966
+ const oldOrder = r?.oldOrder || r;
967
+ const id = oldOrder?.id || r?.id;
968
+ const orderId = oldOrder?.orderId || r?.orderId;
969
+ const newGridId = r?.newGridId || id;
970
+ const newSize = Number.isFinite(Number(r?.newSize))
971
+ ? Number(r.newSize)
972
+ : Number(r?.size || oldOrder?.size || 0);
973
+ const newPrice = Number.isFinite(Number(r?.newPrice))
974
+ ? Number(r.newPrice)
975
+ : Number(r?.price || oldOrder?.price);
976
+ const orderType = r?.type || oldOrder?.type;
977
+ if (!id || !orderId || !newGridId || !orderType || !Number.isFinite(newPrice) || !(newSize > 0))
978
+ continue;
979
+ actions.push({
980
+ type: COW_ACTIONS.UPDATE,
981
+ id,
982
+ orderId,
983
+ newGridId,
984
+ newSize,
985
+ newPrice,
986
+ order: {
987
+ id: newGridId,
988
+ type: orderType,
989
+ price: newPrice,
990
+ size: newSize
991
+ }
992
+ });
993
+ }
994
+ for (const o of ordersToUpdate) {
995
+ const partialOrder = o?.partialOrder || o;
996
+ const id = o?.id || partialOrder?.id;
997
+ const orderId = o?.orderId || partialOrder?.orderId;
998
+ const orderType = o?.type || partialOrder?.type;
999
+ const newSize = Number.isFinite(Number(o?.newSize))
1000
+ ? Number(o.newSize)
1001
+ : Number(partialOrder?.size || 0);
1002
+ if (!id || !orderId)
1003
+ continue;
1004
+ actions.push({
1005
+ type: COW_ACTIONS.UPDATE,
1006
+ id,
1007
+ orderId,
1008
+ newSize,
1009
+ order: {
1010
+ ...(partialOrder || {}),
1011
+ id,
1012
+ orderId,
1013
+ type: orderType,
1014
+ size: newSize
1015
+ }
1016
+ });
1017
+ }
1018
+ for (const o of ordersToPlace) {
1019
+ if (!o?.id)
1020
+ continue;
1021
+ actions.push({ type: COW_ACTIONS.CREATE, id: o.id, order: o });
1022
+ }
1023
+ return actions;
1024
+ }
1025
+ /**
1026
+ * Build a COW result object (workingGrid + actions) from a simple plan.
1027
+ * @param {import('./dexbot_class').DEXBot} bot
1028
+ * @param {Object|Array} plan
1029
+ * @returns {{workingGrid: import('./types').WorkingGrid, workingIndexes: Object, workingBoundary: number, actions: Array}}
1030
+ */
1031
+ function buildCowResultFromPlan(bot, plan) {
1032
+ const workingGrid = new WorkingGrid(bot.manager.orders, {
1033
+ baseVersion: Number.isFinite(Number(bot.manager._gridVersion)) ? bot.manager._gridVersion : 0
1034
+ });
1035
+ const workingBoundary = bot.manager.boundaryIdx;
1036
+ const actions = buildActionsFromPlan(bot, plan);
1037
+ for (const action of actions) {
1038
+ if (action.type === COW_ACTIONS.CANCEL) {
1039
+ const current = workingGrid.get(action.id);
1040
+ if (!current)
1041
+ continue;
1042
+ workingGrid.set(action.id, convertToSpreadPlaceholder(current));
1043
+ }
1044
+ else if (action.type === COW_ACTIONS.CREATE) {
1045
+ if (!action.id || !action.order)
1046
+ continue;
1047
+ const current = workingGrid.get(action.id) || { id: action.id };
1048
+ workingGrid.set(action.id, {
1049
+ ...current,
1050
+ ...action.order,
1051
+ id: action.id,
1052
+ state: ORDER_STATES.VIRTUAL,
1053
+ orderId: null
1054
+ });
1055
+ }
1056
+ else if (action.type === COW_ACTIONS.UPDATE) {
1057
+ if (action.newGridId && action.newGridId !== action.id) {
1058
+ const current = workingGrid.get(action.id);
1059
+ if (current) {
1060
+ workingGrid.set(action.id, convertToSpreadPlaceholder(current));
1061
+ }
1062
+ const targetId = action.newGridId;
1063
+ const targetCurrent = workingGrid.get(targetId) || { id: targetId };
1064
+ const rotatedSize = Number.isFinite(Number(action.newSize))
1065
+ ? Number(action.newSize)
1066
+ : Number(targetCurrent.size || 0);
1067
+ const rotatedPrice = Number.isFinite(Number(action.newPrice))
1068
+ ? Number(action.newPrice)
1069
+ : Number(action.order?.price ?? targetCurrent.price);
1070
+ workingGrid.set(targetId, {
1071
+ ...targetCurrent,
1072
+ ...(action.order || {}),
1073
+ id: targetId,
1074
+ size: rotatedSize,
1075
+ price: rotatedPrice,
1076
+ state: ORDER_STATES.VIRTUAL,
1077
+ orderId: null
1078
+ });
1079
+ continue;
1080
+ }
1081
+ const current = workingGrid.get(action.id);
1082
+ if (!current)
1083
+ continue;
1084
+ const newSize = Number.isFinite(Number(action.newSize))
1085
+ ? Number(action.newSize)
1086
+ : Number(current.size || 0);
1087
+ workingGrid.set(action.id, {
1088
+ ...current,
1089
+ ...(action.order || {}),
1090
+ id: action.id,
1091
+ orderId: action.orderId || current.orderId,
1092
+ size: newSize
1093
+ });
1094
+ }
1095
+ }
1096
+ return {
1097
+ workingGrid,
1098
+ workingIndexes: workingGrid.getIndexes(),
1099
+ workingBoundary,
1100
+ actions
1101
+ };
1102
+ }
1103
+ /**
1104
+ * Restore skipped update slots in the working grid to master state.
1105
+ * @param {import('./dexbot_class').DEXBot} bot
1106
+ * @param {import('./types').WorkingGrid} workingGrid
1107
+ * @param {Set<string>} skippedSlotIds
1108
+ * @param {number} [skippedCount=0]
1109
+ */
1110
+ function restoreSkippedUpdateSlotsInWorkingGrid(bot, workingGrid, skippedSlotIds, skippedCount = 0) {
1111
+ if (!workingGrid || !skippedSlotIds || skippedSlotIds.size === 0) {
1112
+ return;
1113
+ }
1114
+ const masterVersion = Number.isFinite(Number(bot.manager?._gridVersion))
1115
+ ? Number(bot.manager._gridVersion)
1116
+ : undefined;
1117
+ for (const slotId of skippedSlotIds) {
1118
+ workingGrid.syncFromMaster(bot.manager.orders, slotId, masterVersion);
1119
+ }
1120
+ bot.manager.logger.log(`[COW] Restored ${skippedSlotIds.size} slot(s) after ${skippedCount} skipped update action(s).`, 'debug');
1121
+ }
1122
+ /**
1123
+ * COW broadcast: Execute blockchain operations and commit working grid on success.
1124
+ * @param {import('./dexbot_class').DEXBot} bot
1125
+ * @param {Object} cowResult
1126
+ * @returns {Promise<Object>}
1127
+ */
1128
+ async function updateOrdersOnChainBatchCOW(bot, cowResult) {
1129
+ bot._currentCycleId = (Number.isFinite(Number(bot._currentCycleId)) ? Number(bot._currentCycleId) : 0) + 1;
1130
+ const { workingGrid, workingIndexes, workingBoundary, actions } = cowResult;
1131
+ if (bot.config.dryRun) {
1132
+ const cancelCount = actions.filter((a) => a.type === COW_ACTIONS.CANCEL).length;
1133
+ const createCount = actions.filter((a) => a.type === COW_ACTIONS.CREATE).length;
1134
+ const updateCount = actions.filter((a) => a.type === COW_ACTIONS.UPDATE).length;
1135
+ if (cancelCount > 0)
1136
+ bot.manager.logger.log(`Dry run: would cancel ${cancelCount} orders`, 'info');
1137
+ if (createCount > 0)
1138
+ bot.manager.logger.log(`Dry run: would place ${createCount} new orders`, 'info');
1139
+ if (updateCount > 0)
1140
+ bot.manager.logger.log(`Dry run: would update ${updateCount} orders`, 'info');
1141
+ return { executed: true, hadRotation: false };
1142
+ }
1143
+ const createSlotValidation = validateCreateTargetSlots(actions, bot.manager?.orders);
1144
+ if (!createSlotValidation.isValid) {
1145
+ for (const violation of createSlotValidation.violations) {
1146
+ bot.manager.logger.log(`[COW] Rejecting CREATE for occupied slot ${violation.targetId}: ` +
1147
+ `existing orderId=${violation.currentOrderId}, type=${violation.currentType}, state=${violation.currentState}`, 'error');
1148
+ }
1149
+ return {
1150
+ executed: false,
1151
+ aborted: true,
1152
+ reason: 'CREATE_SLOT_OCCUPIED',
1153
+ violations: createSlotValidation.violations,
1154
+ hadRotation: false
1155
+ };
1156
+ }
1157
+ const hasCreateActions = actions.some((action) => action.type === COW_ACTIONS.CREATE);
1158
+ if (hasCreateActions && bot.manager?._recoveryExhaustedAt) {
1159
+ const exhaustedAge = Date.now() - bot.manager._recoveryExhaustedAt;
1160
+ bot.manager.logger.log?.(`[RECOVERY-EXHAUSTED] Blocking ${actions.filter((a) => a.type === COW_ACTIONS.CREATE).length} CREATE(s) ` +
1161
+ `(exhausted ${(exhaustedAge / 1000).toFixed(0)}s ago). ` +
1162
+ `Waiting for next fill or sync cycle to reset recovery state.`, 'warn');
1163
+ return {
1164
+ executed: false,
1165
+ aborted: true,
1166
+ reason: 'RECOVERY_EXHAUSTED',
1167
+ hadRotation: false
1168
+ };
1169
+ }
1170
+ const unmatchedChainOrders = Array.isArray(bot.manager?._lastUnmatchedChainOrders)
1171
+ ? bot.manager._lastUnmatchedChainOrders
1172
+ : [];
1173
+ const pendingBroadcasts = (bot.manager && bot.manager._pendingBroadcasts instanceof Map)
1174
+ ? Array.from(bot.manager._pendingBroadcasts.values())
1175
+ : [];
1176
+ if (hasCreateActions && (unmatchedChainOrders.length > 0 || pendingBroadcasts.length > 0)) {
1177
+ if (pendingBroadcasts.length > 0) {
1178
+ bot.manager.logger.log(`[COW] Rejecting CREATE batch: ${pendingBroadcasts.length} pending broadcast(s) from a prior uncertain ` +
1179
+ `broadcast. Running recovery before placing replacement orders.`, 'error');
1180
+ if (typeof bot.manager.requestStructuralGridResync === 'function') {
1181
+ if (bot.manager._recoveryState)
1182
+ bot.manager._recoveryState = { ...bot.manager._recoveryState, structuralResyncRequested: true };
1183
+ await bot.manager.requestStructuralGridResync('pending broadcasts before COW create', { pendingBroadcasts: pendingBroadcasts.map((p) => p.slotId) });
1184
+ }
1185
+ try {
1186
+ await reconcileAfterUncertainBroadcast(bot, new BroadcastUncertainError('rejected CREATE batch had pending broadcasts', {
1187
+ operations: pendingBroadcasts.map((p) => p.order),
1188
+ accountName: bot.account,
1189
+ batchId: bot._currentBatchId || null,
1190
+ payload: null,
1191
+ timeoutMs: null
1192
+ }), []);
1193
+ }
1194
+ catch (recoverErr) {
1195
+ bot.manager.logger.log(`[COW] Recovery from pending broadcasts failed: ${recoverErr?.message || recoverErr}`, 'error');
1196
+ }
1197
+ return {
1198
+ executed: false,
1199
+ aborted: true,
1200
+ reason: 'PENDING_BROADCASTS',
1201
+ hadRotation: false
1202
+ };
1203
+ }
1204
+ const unmatchedSample = unmatchedChainOrders
1205
+ .slice(0, 3)
1206
+ .map((o) => formatUnmatchedChainOrderForLog(o))
1207
+ .join(' | ');
1208
+ bot.manager.logger.log(`[COW] ${unmatchedChainOrders.length} unmatched chain order(s) blocking CREATES ` +
1209
+ (unmatchedSample ? `(${unmatchedSample})` : '') +
1210
+ ` — adopting via sync instead of cancelling`, 'info');
1211
+ try {
1212
+ const accountRef = bot.account;
1213
+ const freshSnapshot = await chainOrders.readOpenOrders(accountRef);
1214
+ if (freshSnapshot && freshSnapshot.length > 0) {
1215
+ const syncResult = await bot.manager.syncFromOpenOrders(freshSnapshot, {
1216
+ skipAccounting: true,
1217
+ });
1218
+ if (syncResult && Array.isArray(syncResult.unmatchedChainOrders)) {
1219
+ const processed = (syncResult.filledOrders?.length || 0) +
1220
+ (syncResult.updatedOrders?.length || 0) +
1221
+ (syncResult.ordersNeedingCorrection?.length || 0);
1222
+ if (processed > 0) {
1223
+ bot.manager._lastUnmatchedChainOrders = syncResult.unmatchedChainOrders;
1224
+ bot.manager.logger.log(`[COW] Adopted chain order(s) via sync: ${processed} processed, ` +
1225
+ `${syncResult.unmatchedChainOrders.length} still unmatched`, 'info');
1226
+ }
1227
+ else {
1228
+ const syncUnmatchedCount = syncResult.unmatchedChainOrders.length;
1229
+ bot.manager.logger.log(`[COW] Sync returned without processing (processed=0, ` +
1230
+ `unmatched=${syncUnmatchedCount} in result, ` +
1231
+ `_lastUnmatchedChainOrders=${unmatchedChainOrders.length}). ` +
1232
+ `Structural resync will handle adoption.`, syncUnmatchedCount > 0 ? 'warn' : 'debug');
1233
+ if (syncUnmatchedCount > 0 && syncUnmatchedCount !== unmatchedChainOrders.length) {
1234
+ bot.manager._lastUnmatchedChainOrders = syncResult.unmatchedChainOrders.map((o) => ({ ...o }));
1235
+ bot.manager.logger.log(`[COW] Updated _lastUnmatchedChainOrders from sync result: ` +
1236
+ `${unmatchedChainOrders.length} → ${syncUnmatchedCount}`, 'debug');
1237
+ }
1238
+ }
1239
+ }
1240
+ }
1241
+ }
1242
+ catch (syncErr) {
1243
+ bot.manager.logger.log(`[COW] Failed to sync/unmatched orders: ${syncErr?.message || syncErr}`, 'warn');
1244
+ }
1245
+ if (typeof bot.manager.requestStructuralGridResync === 'function') {
1246
+ if (bot.manager._recoveryState)
1247
+ bot.manager._recoveryState = { ...bot.manager._recoveryState, structuralResyncRequested: true };
1248
+ await bot.manager.requestStructuralGridResync('unmatched chain orders before COW create', { unmatchedChainOrders: unmatchedChainOrders });
1249
+ }
1250
+ bot.manager.logger.log(`[COW] Rejecting CREATE batch after sync: working grid invalidated by master mutation`, 'info');
1251
+ return {
1252
+ executed: false,
1253
+ aborted: true,
1254
+ reason: 'UNMATCHED_CHAIN_ORDERS',
1255
+ hadRotation: false
1256
+ };
1257
+ }
1258
+ const { assetA, assetB } = bot.manager.assets;
1259
+ const operations = [];
1260
+ const opContexts = [];
1261
+ const skippedUpdateSlotIds = new Set();
1262
+ let skippedUpdateCount = 0;
1263
+ const idsToLock = new Set();
1264
+ for (const action of actions) {
1265
+ if (action.type === COW_ACTIONS.CANCEL && action.orderId) {
1266
+ idsToLock.add(action.orderId);
1267
+ if (action.id)
1268
+ idsToLock.add(action.id);
1269
+ }
1270
+ else if (action.type === COW_ACTIONS.CREATE && action.id) {
1271
+ idsToLock.add(action.id);
1272
+ }
1273
+ else if (action.type === COW_ACTIONS.UPDATE && action.orderId) {
1274
+ idsToLock.add(action.orderId);
1275
+ if (action.id)
1276
+ idsToLock.add(action.id);
1277
+ }
1278
+ }
1279
+ bot.manager.lockOrders(idsToLock);
1280
+ try {
1281
+ bot._batchInFlight = true;
1282
+ bot._markGridActivity('batch start');
1283
+ bot.manager._setRebalanceState(REBALANCE_STATES.BROADCASTING);
1284
+ bot.manager.startBroadcasting();
1285
+ for (const action of actions) {
1286
+ if (action.type === COW_ACTIONS.CANCEL) {
1287
+ try {
1288
+ const op = await chainOrders.buildCancelOrderOp(bot.account, action.orderId);
1289
+ operations.push(op);
1290
+ const order = bot.manager.orders.get(action.id) || { id: action.id, orderId: action.orderId };
1291
+ opContexts.push({ kind: 'cancel', order });
1292
+ }
1293
+ catch (err) {
1294
+ const orderNotFound = /\bnot found\b/i.test(getErrorMessage(err)) || /\bdoes not exist\b/i.test(getErrorMessage(err));
1295
+ if (orderNotFound) {
1296
+ bot.manager.logger.log(`[COW] Cancel skipped for ${action.id} (${action.orderId}): order already removed from chain`, 'debug');
1297
+ }
1298
+ else {
1299
+ bot.manager.logger.log(`Failed to prepare cancel op for ${action.id}: ${getErrorMessage(err)}`, 'error');
1300
+ }
1301
+ }
1302
+ }
1303
+ else if (action.type === COW_ACTIONS.CREATE) {
1304
+ try {
1305
+ const order = action.order;
1306
+ const sizeValidation = validateOrderSizeForExecution(bot, order.size, order.type, order, order.size);
1307
+ if (!sizeValidation.isValid) {
1308
+ bot.manager.logger.log(`Skipping create op for ${action.id}: ${sizeValidation.reason}`, 'warn');
1309
+ continue;
1310
+ }
1311
+ const liveSlot = bot.manager.orders.get(order.id);
1312
+ const plannedPrice = Number(order.price);
1313
+ const livePrice = liveSlot ? Number(liveSlot.price) : NaN;
1314
+ const priceDrift = Number.isFinite(plannedPrice) && Number.isFinite(livePrice)
1315
+ ? Math.abs(livePrice - plannedPrice)
1316
+ : 0;
1317
+ const effectiveOrder = (priceDrift > 0)
1318
+ ? { ...order, price: livePrice, size: order.size, type: order.type }
1319
+ : order;
1320
+ if (priceDrift > 0) {
1321
+ bot.manager.logger.log(`[COW] Pre-broadcast price freshness: slot ${order.id} ` +
1322
+ `drifted from planned=${plannedPrice} to live=${livePrice} ` +
1323
+ `(diff=${priceDrift}); rebuilding CREATE op with live price.`, 'debug');
1324
+ }
1325
+ const createPrice = effectiveOrder.price;
1326
+ const createSize = effectiveOrder.size;
1327
+ const priceCollision = findPriceCollision(bot.manager.orders.values(), order.id, createPrice, createSize, order.type, bot.manager.assets, isOrderPlaced);
1328
+ if (priceCollision) {
1329
+ bot.manager.logger.log(`[COW] Skipping CREATE for ${order.id} at ${Format.formatPrice6(createPrice)}: ` +
1330
+ `existing placed order ${priceCollision.id} (${priceCollision.orderId}) ` +
1331
+ `already at price ${Format.formatPrice6(priceCollision.price)}. ` +
1332
+ `The next reconcile cycle will resolve the mismatch.`, 'warn');
1333
+ continue;
1334
+ }
1335
+ const batchCollision = findPriceCollision(opContexts, order.id, createPrice, createSize, order.type, bot.manager.assets, (ctx) => ctx.kind === 'create');
1336
+ if (batchCollision) {
1337
+ bot.manager.logger.log(`[COW] Skipping CREATE for ${order.id} at ${Format.formatPrice6(createPrice)}: ` +
1338
+ `same-batch CREATE ${batchCollision.id} already at ` +
1339
+ `price ${Format.formatPrice6(batchCollision.order.price)}. ` +
1340
+ `The next reconcile cycle will resolve the mismatch.`, 'warn');
1341
+ continue;
1342
+ }
1343
+ const args = buildCreateOrderArgs(effectiveOrder, assetA, assetB);
1344
+ const buildResult = await chainOrders.buildCreateOrderOp(bot.account, args.amountToSell, args.sellAssetId, args.minToReceive, args.receiveAssetId, null);
1345
+ if (!buildResult) {
1346
+ bot.manager.logger.log(`Skipping create op for ${action.id}: amounts would round to 0 on blockchain`, 'warn');
1347
+ continue;
1348
+ }
1349
+ operations.push(buildResult.op);
1350
+ opContexts.push({ kind: 'create', id: order.id, order: effectiveOrder, args, finalInts: buildResult.finalInts });
1351
+ recordPendingBroadcast(bot, {
1352
+ opIndex: operations.length - 1,
1353
+ ctxIndex: opContexts.length - 1,
1354
+ order: effectiveOrder,
1355
+ finalInts: buildResult.finalInts
1356
+ });
1357
+ }
1358
+ catch (err) {
1359
+ bot.manager.logger.log(`Failed to prepare create op for ${action.id}: ${getErrorMessage(err)}`, 'error');
1360
+ }
1361
+ }
1362
+ else if (action.type === COW_ACTIONS.UPDATE) {
1363
+ try {
1364
+ if (action.newGridId && action.newGridId !== action.id) {
1365
+ const masterOrder = bot.manager.orders.get(action.id);
1366
+ const orderType = action.order?.type || masterOrder?.type;
1367
+ const newPrice = Number.isFinite(Number(action.newPrice))
1368
+ ? Number(action.newPrice)
1369
+ : Number(action.order?.price);
1370
+ const newSize = Number.isFinite(Number(action.newSize))
1371
+ ? Number(action.newSize)
1372
+ : Number(action.order?.size || 0);
1373
+ if (!masterOrder || !action.orderId || !orderType || !Number.isFinite(newPrice) || newSize <= 0) {
1374
+ continue;
1375
+ }
1376
+ const rotationSizeValidation = validateOrderSizeForExecution(bot, newSize, orderType, action.order, newSize);
1377
+ if (!rotationSizeValidation.isValid) {
1378
+ bot.manager.logger.log(`Skipping rotation update ${action.id} -> ${action.newGridId}: ${rotationSizeValidation.reason}`, 'warn');
1379
+ continue;
1380
+ }
1381
+ const { amountToSell, minToReceive } = buildCreateOrderArgs({ type: orderType, size: newSize, price: newPrice }, assetA, assetB);
1382
+ const buildResult = await chainOrders.buildUpdateOrderOp(bot.account, action.orderId, { amountToSell, minToReceive, newPrice, orderType }, masterOrder.rawOnChain || null);
1383
+ if (!buildResult) {
1384
+ skippedUpdateCount++;
1385
+ if (action.id)
1386
+ skippedUpdateSlotIds.add(action.id);
1387
+ if (action.newGridId)
1388
+ skippedUpdateSlotIds.add(action.newGridId);
1389
+ bot.manager.logger.log(`[COW] Skipping rotation update ${action.id} -> ${action.newGridId}: no blockchain delta`, 'debug');
1390
+ continue;
1391
+ }
1392
+ operations.push(buildResult.op);
1393
+ opContexts.push({
1394
+ kind: 'rotation',
1395
+ rotation: {
1396
+ oldOrder: { ...masterOrder },
1397
+ newGridId: action.newGridId,
1398
+ newPrice,
1399
+ newSize,
1400
+ type: orderType
1401
+ },
1402
+ finalInts: buildResult.finalInts
1403
+ });
1404
+ continue;
1405
+ }
1406
+ const newSize = Number.isFinite(Number(action.newSize))
1407
+ ? Number(action.newSize)
1408
+ : Number(action.order?.size || 0);
1409
+ const masterOrder = bot.manager.orders.get(action.id);
1410
+ const orderType = action.order?.type || masterOrder?.type;
1411
+ const cachedRawOnChain = masterOrder?.rawOnChain || action.order?.rawOnChain || null;
1412
+ const op = await chainOrders.buildUpdateOrderOp(bot.account, action.orderId, { amountToSell: newSize, orderType }, cachedRawOnChain);
1413
+ if (!op) {
1414
+ skippedUpdateCount++;
1415
+ if (action.id)
1416
+ skippedUpdateSlotIds.add(action.id);
1417
+ if (action.newGridId)
1418
+ skippedUpdateSlotIds.add(action.newGridId);
1419
+ bot.manager.logger.log(`[COW] Skipping size update ${action.id} (${action.orderId}): no blockchain delta`, 'debug');
1420
+ continue;
1421
+ }
1422
+ operations.push(op.op);
1423
+ const partialOrder = masterOrder || {
1424
+ id: action.id,
1425
+ orderId: action.orderId,
1426
+ type: orderType
1427
+ };
1428
+ opContexts.push({ kind: 'size-update', updateInfo: { partialOrder, newSize }, finalInts: op.finalInts });
1429
+ }
1430
+ catch (err) {
1431
+ const orderNotFound = /\bnot found\b/i.test(getErrorMessage(err)) || /\bdoes not exist\b/i.test(getErrorMessage(err));
1432
+ if (orderNotFound) {
1433
+ try {
1434
+ const fbOrder = action.order || bot.manager.orders.get(action.id);
1435
+ const fbType = fbOrder?.type;
1436
+ const fbSize = action.newSize || fbOrder?.size || 0;
1437
+ const targetSlotId = action.newGridId || action.id;
1438
+ const plannedPrice = action.newPrice || action.order?.price || 0;
1439
+ const liveSlotForPrice = bot.manager.orders.get(targetSlotId);
1440
+ const livePrice = liveSlotForPrice ? Number(liveSlotForPrice.price) : NaN;
1441
+ const priceDrift = Number.isFinite(plannedPrice) && Number.isFinite(livePrice)
1442
+ ? Math.abs(livePrice - plannedPrice)
1443
+ : 0;
1444
+ const fbPrice = (priceDrift > 0) ? livePrice : plannedPrice;
1445
+ if (priceDrift > 0) {
1446
+ bot.manager.logger.log(`[COW] CREATE fallback price drift for ${action.id} -> ${targetSlotId}: ` +
1447
+ `planned=${plannedPrice} live=${livePrice} (diff=${priceDrift})`, 'debug');
1448
+ }
1449
+ const sizeCheck = validateOrderSizeForExecution(bot, fbSize, fbType, fbOrder, fbSize);
1450
+ if (!sizeCheck.isValid) {
1451
+ bot.manager.logger.log(`[COW] CREATE fallback for ${action.id} rejected by size validation: ${sizeCheck.reason}`, 'warn');
1452
+ }
1453
+ else if (fbType && fbSize > 0 && fbPrice > 0) {
1454
+ const fbCollision = findPriceCollision(bot.manager.orders.values(), targetSlotId, fbPrice, fbSize, fbType, bot.manager.assets, isOrderPlaced);
1455
+ if (fbCollision) {
1456
+ bot.manager.logger.log(`[COW] Skipping CREATE fallback for ${targetSlotId} at ${Format.formatPrice6(fbPrice)}: ` +
1457
+ `existing placed order ${fbCollision.id} (${fbCollision.orderId}) ` +
1458
+ `already at price ${Format.formatPrice6(fbCollision.price)}.`, 'warn');
1459
+ continue;
1460
+ }
1461
+ const fbBatchCollision = findPriceCollision(opContexts, targetSlotId, fbPrice, fbSize, fbType, bot.manager.assets, (ctx) => ctx.kind === 'create');
1462
+ if (fbBatchCollision) {
1463
+ bot.manager.logger.log(`[COW] Skipping CREATE fallback for ${targetSlotId} at ${Format.formatPrice6(fbPrice)}: ` +
1464
+ `same-batch CREATE ${fbBatchCollision.id} already at ` +
1465
+ `price ${Format.formatPrice6(fbBatchCollision.order.price)}.`, 'warn');
1466
+ continue;
1467
+ }
1468
+ const fbArgs = buildCreateOrderArgs({ type: fbType, size: fbSize, price: fbPrice }, assetA, assetB);
1469
+ const fbResult = await chainOrders.buildCreateOrderOp(bot.account, fbArgs.amountToSell, fbArgs.sellAssetId, fbArgs.minToReceive, fbArgs.receiveAssetId, null);
1470
+ if (fbResult) {
1471
+ operations.push(fbResult.op);
1472
+ opContexts.push({
1473
+ kind: 'create',
1474
+ id: targetSlotId,
1475
+ order: { id: targetSlotId, type: fbType, price: fbPrice, size: fbSize },
1476
+ args: { amountToSell: fbArgs.amountToSell, minToReceive: fbArgs.minToReceive },
1477
+ finalInts: fbResult.finalInts
1478
+ });
1479
+ recordPendingBroadcast(bot, {
1480
+ opIndex: operations.length - 1,
1481
+ ctxIndex: opContexts.length - 1,
1482
+ order: { id: targetSlotId, type: fbType, price: fbPrice, size: fbSize },
1483
+ finalInts: fbResult.finalInts
1484
+ });
1485
+ bot.manager.logger.log(`[COW] Recovered "not found" for ${action.id}: converted UPDATE to CREATE for slot ${targetSlotId}`, 'warn');
1486
+ continue;
1487
+ }
1488
+ }
1489
+ }
1490
+ catch (fbErr) {
1491
+ bot.manager.logger.log(`[COW] CREATE fallback also failed for ${action.id}: ${getErrorMessage(fbErr)}`, 'warn');
1492
+ }
1493
+ }
1494
+ bot.manager.logger.log(`Failed to prepare update op for ${action.id}: ${getErrorMessage(err)}`, 'error');
1495
+ }
1496
+ }
1497
+ }
1498
+ if (skippedUpdateCount > 0) {
1499
+ restoreSkippedUpdateSlotsInWorkingGrid(bot, workingGrid, skippedUpdateSlotIds, skippedUpdateCount);
1500
+ }
1501
+ if (operations.length === 0) {
1502
+ bot.manager._setRebalanceState(REBALANCE_STATES.NORMAL);
1503
+ return { executed: false, hadRotation: false };
1504
+ }
1505
+ const validation = validateOperationFunds(bot, operations, assetA, assetB);
1506
+ bot.manager.logger.log(validation.summary, validation.isValid ? 'info' : 'warn');
1507
+ if (!validation.isValid) {
1508
+ bot.manager.logger.log(`Skipping batch broadcast: ${validation.violations.length} fund violation(s) detected`, 'warn');
1509
+ bot.manager._setRebalanceState(REBALANCE_STATES.NORMAL);
1510
+ return { executed: false, hadRotation: false };
1511
+ }
1512
+ await bot._ensureCredentialDaemonWritable('COW batch broadcast');
1513
+ bot.manager.logger.log(`[COW] Broadcasting batch with ${operations.length} operations...`, 'info');
1514
+ bot._lastBroadcastHeartbeatAt = Date.now();
1515
+ const execution = await executeWithRetryOnUncertain(bot, operations, opContexts);
1516
+ const result = execution.result;
1517
+ const executedContexts = execution.opContexts;
1518
+ bot.manager.pauseFundRecalc();
1519
+ try {
1520
+ bot.manager._throwOnIllegalState = true;
1521
+ if (result.success) {
1522
+ const preCommitResults = extractOperationResults(result, 'pre-commit-integrity', bot.manager?.logger?.log?.bind(bot.manager?.logger));
1523
+ const missingCreateResults = findMissingCreateResultContexts(preCommitResults, executedContexts);
1524
+ if (missingCreateResults.length > 0) {
1525
+ const missingSlots = missingCreateResults
1526
+ .map((item) => item.ctx?.order?.id || item.ctx?.id || `op-${item.index}`)
1527
+ .join(', ');
1528
+ bot.manager.logger.log(`[COW] Refusing to commit working grid: ${missingCreateResults.length} CREATE op(s) ` +
1529
+ `returned no chainOrderId (${missingSlots}). Discarding working grid and syncing from chain.`, 'error');
1530
+ bot.manager._clearWorkingGridRef();
1531
+ bot.manager._setRebalanceState(REBALANCE_STATES.NORMAL);
1532
+ markMissingCreateResultsAsStructuralBlocker(bot, missingCreateResults);
1533
+ await recoverAfterMissingCreateResults(bot, 'missing create operation results');
1534
+ return {
1535
+ executed: false,
1536
+ hadRotation: false,
1537
+ missingCreateResults: missingCreateResults.map((item) => ({
1538
+ index: item.index,
1539
+ slotId: item.ctx?.order?.id || item.ctx?.id || null
1540
+ }))
1541
+ };
1542
+ }
1543
+ bot.manager.logger.log('[COW] Blockchain success - committing working grid to master', 'info');
1544
+ await bot.manager._commitWorkingGrid(workingGrid, workingIndexes, workingBoundary, { skipRecalc: true });
1545
+ const batchResult = await processBatchResults(bot, result, executedContexts);
1546
+ const persistResult = await bot.manager.persistGrid();
1547
+ if (persistResult && (persistResult.skipped || persistResult.isValid === false)) {
1548
+ bot.manager.logger.log(`[COW][PERSIST-GUARD] First persist attempt was ` +
1549
+ `${persistResult.skipped ? 'skipped' : 'invalid'} ` +
1550
+ `(${persistResult.reason || 'no reason'}); retrying once before ` +
1551
+ `clearing working grid reference.`, 'warn');
1552
+ bot.manager._persistenceWarning = persistResult;
1553
+ const retryResult = await bot.manager.persistGrid();
1554
+ if (retryResult && (retryResult.skipped || retryResult.isValid === false)) {
1555
+ bot.manager.logger.log(`[COW][PERSIST-GUARD] Retry also skipped/invalid ` +
1556
+ `(${retryResult.reason || 'no reason'}). Master grid in memory ` +
1557
+ `is ahead of disk snapshot; structural resync requested.`, 'error');
1558
+ if (typeof bot.manager.requestStructuralGridResync === 'function') {
1559
+ bot.manager._recoveryState = { ...bot.manager._recoveryState, structuralResyncRequested: true };
1560
+ await bot.manager.requestStructuralGridResync('persistence guard triggered after COW batch', { persistReason: retryResult.reason || 'unknown' });
1561
+ }
1562
+ }
1563
+ else {
1564
+ delete bot.manager._persistenceWarning;
1565
+ }
1566
+ }
1567
+ else if (bot.manager._persistenceWarning) {
1568
+ delete bot.manager._persistenceWarning;
1569
+ }
1570
+ bot._metrics.batchesExecuted++;
1571
+ bot.manager._clearWorkingGridRef();
1572
+ clearPendingBroadcasts(bot.manager?._pendingBroadcasts);
1573
+ return { ...batchResult, executed: true, hadRotation: true };
1574
+ }
1575
+ else {
1576
+ bot.manager.logger.log('[COW] Blockchain failed - working grid discarded, master unchanged', 'warn');
1577
+ bot.manager._clearWorkingGridRef();
1578
+ clearPendingBroadcasts(bot.manager?._pendingBroadcasts);
1579
+ return { ...result, executed: false, hadRotation: false };
1580
+ }
1581
+ }
1582
+ finally {
1583
+ bot.manager._throwOnIllegalState = false;
1584
+ await bot.manager.resumeFundRecalc();
1585
+ bot.manager.stopBroadcasting();
1586
+ const createCount = actions.filter((a) => a.type === COW_ACTIONS.CREATE).length;
1587
+ const cancelCount = actions.filter((a) => a.type === COW_ACTIONS.CANCEL).length;
1588
+ bot.manager.logger.logFundsStatus(bot.manager, `AFTER COW batch (created=${createCount}, cancelled=${cancelCount})`);
1589
+ }
1590
+ }
1591
+ catch (err) {
1592
+ bot.manager.logger.log(`[COW] Batch transaction failed: ${getErrorMessage(err)}`, 'error');
1593
+ if (err?.partialOnChainState) {
1594
+ bot.manager.logger.log(`[COW] Non-atomic grouped execution detected (${err.groupsBroadcast}/${err.groupsTotal} groups broadcast). Local rollback cannot undo confirmed on-chain operations; next sync/reconcile will converge state.`, 'warn');
1595
+ }
1596
+ bot.manager.stopBroadcasting();
1597
+ bot.manager._clearWorkingGridRef();
1598
+ if (err instanceof BroadcastUncertainError) {
1599
+ return await reconcileAfterUncertainBroadcast(bot, err, opContexts);
1600
+ }
1601
+ const hardAbortResult = await bot._handleBatchHardAbort(err, 'COW batch processing', operations.length);
1602
+ if (hardAbortResult)
1603
+ return hardAbortResult;
1604
+ const staleOrderIds = new Set();
1605
+ const patterns = [
1606
+ /Limit order (1\.7\.\d+) does not exist/g,
1607
+ /Unable to find Object (1\.7\.\d+)/g,
1608
+ /object (1\.7\.\d+) (?:does not exist|not found)/gi
1609
+ ];
1610
+ for (const pattern of patterns) {
1611
+ let m;
1612
+ while ((m = pattern.exec(getErrorMessage(err))) !== null) {
1613
+ staleOrderIds.add(m[1]);
1614
+ }
1615
+ }
1616
+ if (/Cannot deduct all or more from order than order contains/.test(getErrorMessage(err))) {
1617
+ return await bot._recoverBatchSizeDrift(err, opContexts);
1618
+ }
1619
+ if (staleOrderIds.size > 0) {
1620
+ return await bot._recoverExplicitStaleOrders(staleOrderIds, 'cow-stale-order-cleanup');
1621
+ }
1622
+ throw err;
1623
+ }
1624
+ finally {
1625
+ bot._batchInFlight = false;
1626
+ bot._markGridActivity('batch end');
1627
+ bot.manager.unlockOrders(idsToLock);
1628
+ if (!bot._shuttingDown && bot._incomingFillQueue.length > 0) {
1629
+ bot._scheduleFillConsumerRestart(chainOrders);
1630
+ }
1631
+ }
1632
+ }
1633
+ /**
1634
+ * Process results from batch transaction execution.
1635
+ * Updates order state, synchronizes with chain, and deducts BTS fees.
1636
+ * @param {import('./dexbot_class').DEXBot} bot
1637
+ * @param {Object} result
1638
+ * @param {Array} opContexts
1639
+ * @returns {Object} Result with { executed: boolean, hadRotation: boolean }
1640
+ */
1641
+ async function processBatchResults(bot, result, opContexts) {
1642
+ const results = extractOperationResults(result, 'processBatchResults', bot.manager?.logger?.log?.bind(bot.manager?.logger));
1643
+ const btsFeeData = getAssetFees('BTS');
1644
+ let hadRotation = false;
1645
+ let updateOperationCount = 0;
1646
+ const updatesToApply = [];
1647
+ for (let i = 0; i < opContexts.length; i++) {
1648
+ const ctx = opContexts[i];
1649
+ const res = results[i];
1650
+ if (ctx.kind === 'cancel') {
1651
+ bot.manager.logger.log(`Cancelled surplus order ${ctx.order.id} (${ctx.order.orderId})`, 'info');
1652
+ const oldOrder = ctx.order;
1653
+ const committedOrder = oldOrder?.id ? bot.manager.orders.get(oldOrder.id) : null;
1654
+ if (oldOrder && committedOrder && bot.manager.accountant) {
1655
+ await bot.manager.accountant.updateOptimisticFreeBalance(oldOrder, committedOrder, 'fill-cancel', btsFeeData?.cancelFee || 0, false);
1656
+ }
1657
+ }
1658
+ else if (ctx.kind === 'size-update') {
1659
+ const oldOrder = ctx.updateInfo.partialOrder;
1660
+ const ord = bot.manager.orders.get(oldOrder.id);
1661
+ if (oldOrder && ord && bot.manager.accountant) {
1662
+ await bot.manager.accountant.updateOptimisticFreeBalance(oldOrder, ord, 'order-update', btsFeeData.updateFee, false);
1663
+ }
1664
+ if (ord) {
1665
+ const updatedSlot = { ...ord, size: ctx.updateInfo.newSize };
1666
+ if (ctx.finalInts) {
1667
+ updatedSlot.rawOnChain = {
1668
+ id: ord.orderId,
1669
+ for_sale: String(ctx.finalInts.sell),
1670
+ sell_price: {
1671
+ base: { amount: String(ctx.finalInts.sell), asset_id: ctx.finalInts.sellAssetId },
1672
+ quote: { amount: String(ctx.finalInts.receive), asset_id: ctx.finalInts.receiveAssetId }
1673
+ }
1674
+ };
1675
+ }
1676
+ updatesToApply.push({ order: updatedSlot, context: 'post-update-metadata' });
1677
+ }
1678
+ bot.manager.logger.log(`Size update complete: ${ctx.updateInfo.partialOrder.orderId}`, 'info');
1679
+ updateOperationCount++;
1680
+ }
1681
+ else if (ctx.kind === 'create') {
1682
+ const chainOrderId = res && res[1];
1683
+ if (chainOrderId) {
1684
+ await bot.manager.synchronizeWithChain({
1685
+ gridOrderId: ctx.order.id, chainOrderId, expectedType: ctx.order.type, fee: btsFeeData.createFee
1686
+ }, 'createOrder');
1687
+ if (ctx.finalInts) {
1688
+ const syncedOrder = bot.manager.orders.get(ctx.order.id);
1689
+ if (syncedOrder) {
1690
+ updatesToApply.push({
1691
+ order: {
1692
+ ...syncedOrder,
1693
+ rawOnChain: {
1694
+ id: chainOrderId,
1695
+ for_sale: String(ctx.finalInts.sell),
1696
+ sell_price: {
1697
+ base: { amount: String(ctx.finalInts.sell), asset_id: ctx.finalInts.sellAssetId },
1698
+ quote: { amount: String(ctx.finalInts.receive), asset_id: ctx.finalInts.receiveAssetId }
1699
+ }
1700
+ }
1701
+ },
1702
+ context: 'post-placement-metadata'
1703
+ });
1704
+ }
1705
+ }
1706
+ bot.manager.logger.log(`Placed ${ctx.order.type} order ${ctx.order.id} -> ${chainOrderId}`, 'info');
1707
+ }
1708
+ else {
1709
+ const fingerprint = [
1710
+ `type=${ctx.order.type || 'unknown'}`,
1711
+ `price=${Format.formatPrice6(ctx.order.price)}`,
1712
+ `size=${Format.formatAmount(ctx.order.size)}`
1713
+ ].join(',');
1714
+ bot.manager.logger.log(`[COW] CRITICAL: Create op for slot ${ctx.order.id} (type=${ctx.order.type}) ` +
1715
+ `returned no chainOrderId. Identify any orphaned on-chain order by local fingerprint ` +
1716
+ `${fingerprint} before cancelling.`, 'error');
1717
+ }
1718
+ }
1719
+ else if (ctx.kind === 'rotation') {
1720
+ hadRotation = true;
1721
+ const { rotation } = ctx;
1722
+ const { oldOrder, newPrice, newGridId, newSize, type } = rotation;
1723
+ if (!newGridId) {
1724
+ const ord = bot.manager.orders.get(oldOrder.id || rotation.id);
1725
+ if (oldOrder && ord && bot.manager.accountant) {
1726
+ await bot.manager.accountant.updateOptimisticFreeBalance(oldOrder, ord, 'order-update', btsFeeData.updateFee, false);
1727
+ }
1728
+ if (ord) {
1729
+ const updatedSlot = { ...ord, size: newSize };
1730
+ if (ctx.finalInts) {
1731
+ updatedSlot.rawOnChain = {
1732
+ id: ord.orderId,
1733
+ for_sale: String(ctx.finalInts.sell),
1734
+ sell_price: {
1735
+ base: { amount: String(ctx.finalInts.sell), asset_id: ctx.finalInts.sellAssetId },
1736
+ quote: { amount: String(ctx.finalInts.receive), asset_id: ctx.finalInts.receiveAssetId }
1737
+ }
1738
+ };
1739
+ }
1740
+ updatesToApply.push({ order: updatedSlot, context: 'post-update-metadata' });
1741
+ }
1742
+ updateOperationCount++;
1743
+ continue;
1744
+ }
1745
+ const slot = bot.manager.orders.get(newGridId);
1746
+ if (!slot) {
1747
+ bot.manager.logger.log(`[ROTATION] Destination slot ${newGridId} missing from master grid after COW commit - skipping activation, sync will reconcile`, 'error');
1748
+ if (oldOrder?.id && oldOrder.id !== newGridId) {
1749
+ const staleSource = bot.manager.orders.get(oldOrder.id);
1750
+ if (staleSource?.orderId) {
1751
+ updatesToApply.push({
1752
+ order: { ...staleSource, state: ORDER_STATES.VIRTUAL, orderId: null, rawOnChain: null },
1753
+ context: 'post-rotation-source-clear'
1754
+ });
1755
+ }
1756
+ }
1757
+ continue;
1758
+ }
1759
+ const updatedSlot = {
1760
+ ...slot,
1761
+ id: newGridId,
1762
+ type,
1763
+ size: newSize,
1764
+ price: newPrice,
1765
+ state: ORDER_STATES.ACTIVE,
1766
+ orderId: oldOrder?.orderId || slot.orderId || null
1767
+ };
1768
+ if (ctx.finalInts) {
1769
+ updatedSlot.rawOnChain = {
1770
+ id: updatedSlot.orderId,
1771
+ for_sale: String(ctx.finalInts.sell),
1772
+ sell_price: {
1773
+ base: { amount: String(ctx.finalInts.sell), asset_id: ctx.finalInts.sellAssetId },
1774
+ quote: { amount: String(ctx.finalInts.receive), asset_id: ctx.finalInts.receiveAssetId }
1775
+ }
1776
+ };
1777
+ }
1778
+ if (oldOrder && updatedSlot && bot.manager.accountant) {
1779
+ await bot.manager.accountant.updateOptimisticFreeBalance(oldOrder, updatedSlot, 'order-update', btsFeeData.updateFee, false);
1780
+ }
1781
+ if (oldOrder?.id && oldOrder.id !== newGridId) {
1782
+ const currentSource = bot.manager.orders.get(oldOrder.id);
1783
+ if (currentSource && currentSource.orderId) {
1784
+ updatesToApply.push({
1785
+ order: {
1786
+ ...currentSource,
1787
+ state: ORDER_STATES.VIRTUAL,
1788
+ orderId: null,
1789
+ rawOnChain: null
1790
+ },
1791
+ context: 'post-rotation-source-clear'
1792
+ });
1793
+ }
1794
+ }
1795
+ updatesToApply.push({ order: updatedSlot, context: 'post-rotation-metadata' });
1796
+ }
1797
+ }
1798
+ if (updatesToApply.length > 0) {
1799
+ await bot.manager.applyGridUpdateBatch(updatesToApply.map((u) => u.order), 'batch-results-process', { skipAccounting: true });
1800
+ }
1801
+ return {
1802
+ executed: true,
1803
+ hadRotation,
1804
+ updateOperationCount
1805
+ };
1806
+ }
1807
+ module.exports = {
1808
+ buildOutsideInPairGroupsForOrders,
1809
+ buildOutsideInPairGroupsForCreateEntries,
1810
+ extractOperationResults,
1811
+ findMissingCreateResultContexts,
1812
+ recoverAfterMissingCreateResults,
1813
+ preserveMissingCreateBlockersAfterRecovery,
1814
+ markMissingCreateResultsAsStructuralBlocker,
1815
+ formatUnmatchedChainOrderForLog,
1816
+ recordPendingBroadcast,
1817
+ clearPendingBroadcasts,
1818
+ buildChainOrderFingerprint,
1819
+ normalizeChainOrderForPendingMatch,
1820
+ findChainOrderForSlot,
1821
+ reconcileAfterUncertainBroadcast,
1822
+ reconcileAfterUncertainBroadcastImpl,
1823
+ autoCancelOneUnmatchedOrphan,
1824
+ shouldExecuteCreatePairMode,
1825
+ executeWithRetryOnUncertain,
1826
+ executeOperationsWithStrategy,
1827
+ validateOperationFunds,
1828
+ resolveIdealSizeForValidation,
1829
+ validateOrderSizeForExecution,
1830
+ buildActionsFromPlan,
1831
+ buildCowResultFromPlan,
1832
+ restoreSkippedUpdateSlotsInWorkingGrid,
1833
+ updateOrdersOnChainBatchCOW,
1834
+ processBatchResults,
1835
+ };
1836
+ //# sourceMappingURL=dexbot_cow_runtime.js.map