dexbot 1.4.24 → 1.5.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 (256) hide show
  1. package/CHANGELOG.md +67 -0
  2. package/README.md +7 -2
  3. package/analysis/README.md +61 -5
  4. package/analysis/ama_fitting/package.json +1 -1
  5. package/analysis/analyze_derivatives.ts +1 -1
  6. package/analysis/bot_key_utils.ts +272 -3
  7. package/analysis/bot_usage/discover_bot_accounts.ts +64 -9
  8. package/analysis/bot_usage/kibana_bot_queries.ts +40 -1
  9. package/analysis/chart_utils.ts +6 -3
  10. package/analysis/grid_correction_check.ts +932 -0
  11. package/analysis/resolve_bot_accounts.ts +199 -0
  12. package/analysis/trade_profitability.ts +36 -8
  13. package/analysis/tradingview/README.md +25 -0
  14. package/analysis/tradingview/analyze_tradingview.ts +2 -2
  15. package/analysis/trend_detection/package.json +1 -1
  16. package/claw/modules/claw_launcher.ts +5 -4
  17. package/claw/modules/credit_runtime_adapter.ts +2 -1
  18. package/claw/modules/dexbot_profiles.ts +4 -3
  19. package/claw/package.json +1 -1
  20. package/claw/runtimes/openclaw-plugin/openclaw.plugin.json +1 -1
  21. package/claw/runtimes/openclaw-plugin/package.json +1 -1
  22. package/claw/tests/test_claw_mcp_transport.ts +2 -2
  23. package/dist/analysis/analyze_derivatives.js +1 -1
  24. package/dist/analysis/bot_key_utils.d.ts +28 -1
  25. package/dist/analysis/bot_key_utils.d.ts.map +1 -1
  26. package/dist/analysis/bot_key_utils.js +385 -3
  27. package/dist/analysis/bot_key_utils.js.map +1 -1
  28. package/dist/analysis/bot_usage/discover_bot_accounts.js +60 -10
  29. package/dist/analysis/bot_usage/discover_bot_accounts.js.map +1 -1
  30. package/dist/analysis/bot_usage/kibana_bot_queries.d.ts +45 -1
  31. package/dist/analysis/bot_usage/kibana_bot_queries.d.ts.map +1 -1
  32. package/dist/analysis/bot_usage/kibana_bot_queries.js +39 -1
  33. package/dist/analysis/bot_usage/kibana_bot_queries.js.map +1 -1
  34. package/dist/analysis/chart_utils.d.ts +2 -1
  35. package/dist/analysis/chart_utils.d.ts.map +1 -1
  36. package/dist/analysis/chart_utils.js +4 -1
  37. package/dist/analysis/chart_utils.js.map +1 -1
  38. package/dist/analysis/grid_correction_check.d.ts +90 -0
  39. package/dist/analysis/grid_correction_check.d.ts.map +1 -0
  40. package/dist/analysis/grid_correction_check.js +901 -0
  41. package/dist/analysis/grid_correction_check.js.map +1 -0
  42. package/dist/analysis/resolve_bot_accounts.d.ts +3 -0
  43. package/dist/analysis/resolve_bot_accounts.d.ts.map +1 -0
  44. package/dist/analysis/resolve_bot_accounts.js +216 -0
  45. package/dist/analysis/resolve_bot_accounts.js.map +1 -0
  46. package/dist/analysis/trade_profitability.d.ts.map +1 -1
  47. package/dist/analysis/trade_profitability.js +40 -8
  48. package/dist/analysis/trade_profitability.js.map +1 -1
  49. package/dist/analysis/tradingview/analyze_tradingview.js +2 -2
  50. package/dist/analysis/tradingview/analyze_tradingview.js.map +1 -1
  51. package/dist/bot.d.ts.map +1 -1
  52. package/dist/bot.js +2 -1
  53. package/dist/bot.js.map +1 -1
  54. package/dist/dexbot.d.ts.map +1 -1
  55. package/dist/dexbot.js +134 -22
  56. package/dist/dexbot.js.map +1 -1
  57. package/dist/market_adapter/ama_signal_runner.js +2 -2
  58. package/dist/market_adapter/inputs/fetch_cex_synthetic_data.js +2 -1
  59. package/dist/market_adapter/inputs/fetch_cex_synthetic_data.js.map +1 -1
  60. package/dist/market_adapter/inputs/fetch_lp_data.d.ts +4 -1
  61. package/dist/market_adapter/inputs/fetch_lp_data.d.ts.map +1 -1
  62. package/dist/market_adapter/inputs/fetch_lp_data.js +3 -2
  63. package/dist/market_adapter/inputs/fetch_lp_data.js.map +1 -1
  64. package/dist/modules/account_bots.d.ts +42 -1
  65. package/dist/modules/account_bots.d.ts.map +1 -1
  66. package/dist/modules/account_bots.js +221 -22
  67. package/dist/modules/account_bots.js.map +1 -1
  68. package/dist/modules/account_orders.d.ts +7 -10
  69. package/dist/modules/account_orders.d.ts.map +1 -1
  70. package/dist/modules/account_orders.js +26 -2
  71. package/dist/modules/account_orders.js.map +1 -1
  72. package/dist/modules/bitshares_client.d.ts +4 -1
  73. package/dist/modules/bitshares_client.d.ts.map +1 -1
  74. package/dist/modules/bitshares_client.js +12 -4
  75. package/dist/modules/bitshares_client.js.map +1 -1
  76. package/dist/modules/bot_settings.d.ts.map +1 -1
  77. package/dist/modules/bot_settings.js +2 -1
  78. package/dist/modules/bot_settings.js.map +1 -1
  79. package/dist/modules/chain_orders.d.ts.map +1 -1
  80. package/dist/modules/chain_orders.js +21 -2
  81. package/dist/modules/chain_orders.js.map +1 -1
  82. package/dist/modules/cli_colors.d.ts +39 -0
  83. package/dist/modules/cli_colors.d.ts.map +1 -0
  84. package/dist/modules/cli_colors.js +42 -0
  85. package/dist/modules/cli_colors.js.map +1 -0
  86. package/dist/modules/config.d.ts.map +1 -1
  87. package/dist/modules/config.js +27 -0
  88. package/dist/modules/config.js.map +1 -1
  89. package/dist/modules/constants.d.ts +14 -1
  90. package/dist/modules/constants.d.ts.map +1 -1
  91. package/dist/modules/constants.js +66 -11
  92. package/dist/modules/constants.js.map +1 -1
  93. package/dist/modules/credit_pricing.d.ts +61 -0
  94. package/dist/modules/credit_pricing.d.ts.map +1 -0
  95. package/dist/modules/credit_pricing.js +237 -0
  96. package/dist/modules/credit_pricing.js.map +1 -0
  97. package/dist/modules/credit_runtime.d.ts +1 -0
  98. package/dist/modules/credit_runtime.d.ts.map +1 -1
  99. package/dist/modules/credit_runtime.js +49 -107
  100. package/dist/modules/credit_runtime.js.map +1 -1
  101. package/dist/modules/dexbot_class.d.ts +25 -0
  102. package/dist/modules/dexbot_class.d.ts.map +1 -1
  103. package/dist/modules/dexbot_class.js +82 -12
  104. package/dist/modules/dexbot_class.js.map +1 -1
  105. package/dist/modules/dexbot_cow_runtime.d.ts +39 -17
  106. package/dist/modules/dexbot_cow_runtime.d.ts.map +1 -1
  107. package/dist/modules/dexbot_cow_runtime.js +875 -134
  108. package/dist/modules/dexbot_cow_runtime.js.map +1 -1
  109. package/dist/modules/dexbot_fill_runtime.d.ts +11 -1
  110. package/dist/modules/dexbot_fill_runtime.d.ts.map +1 -1
  111. package/dist/modules/dexbot_fill_runtime.js +108 -1
  112. package/dist/modules/dexbot_fill_runtime.js.map +1 -1
  113. package/dist/modules/dexbot_maintenance_runtime.d.ts +29 -14
  114. package/dist/modules/dexbot_maintenance_runtime.d.ts.map +1 -1
  115. package/dist/modules/dexbot_maintenance_runtime.js +279 -63
  116. package/dist/modules/dexbot_maintenance_runtime.js.map +1 -1
  117. package/dist/modules/dexbot_startup_runtime.d.ts +1 -0
  118. package/dist/modules/dexbot_startup_runtime.d.ts.map +1 -1
  119. package/dist/modules/dexbot_startup_runtime.js +58 -7
  120. package/dist/modules/dexbot_startup_runtime.js.map +1 -1
  121. package/dist/modules/dexbot_state_recovery.d.ts.map +1 -1
  122. package/dist/modules/dexbot_state_recovery.js +55 -3
  123. package/dist/modules/dexbot_state_recovery.js.map +1 -1
  124. package/dist/modules/fund_registry.d.ts +1 -1
  125. package/dist/modules/fund_registry.js +1 -1
  126. package/dist/modules/graceful_shutdown.d.ts +12 -1
  127. package/dist/modules/graceful_shutdown.d.ts.map +1 -1
  128. package/dist/modules/graceful_shutdown.js +39 -1
  129. package/dist/modules/graceful_shutdown.js.map +1 -1
  130. package/dist/modules/key_store.d.ts.map +1 -1
  131. package/dist/modules/key_store.js +38 -1
  132. package/dist/modules/key_store.js.map +1 -1
  133. package/dist/modules/launcher/adapter_requirement.d.ts +38 -0
  134. package/dist/modules/launcher/adapter_requirement.d.ts.map +1 -0
  135. package/dist/modules/launcher/adapter_requirement.js +141 -0
  136. package/dist/modules/launcher/adapter_requirement.js.map +1 -0
  137. package/dist/modules/launcher/bot_supervisor.d.ts +2 -2
  138. package/dist/modules/launcher/bot_supervisor.d.ts.map +1 -1
  139. package/dist/modules/launcher/bot_supervisor.js +32 -3
  140. package/dist/modules/launcher/bot_supervisor.js.map +1 -1
  141. package/dist/modules/launcher/launch_modes.d.ts.map +1 -1
  142. package/dist/modules/launcher/launch_modes.js +5 -4
  143. package/dist/modules/launcher/launch_modes.js.map +1 -1
  144. package/dist/modules/launcher/monolithic_runtime.d.ts +1 -1
  145. package/dist/modules/launcher/monolithic_runtime.d.ts.map +1 -1
  146. package/dist/modules/launcher/monolithic_runtime.js +12 -8
  147. package/dist/modules/launcher/monolithic_runtime.js.map +1 -1
  148. package/dist/modules/launcher/status_reporting.d.ts +6 -6
  149. package/dist/modules/launcher/status_reporting.d.ts.map +1 -1
  150. package/dist/modules/launcher/status_reporting.js +9 -6
  151. package/dist/modules/launcher/status_reporting.js.map +1 -1
  152. package/dist/modules/order/accounting.d.ts.map +1 -1
  153. package/dist/modules/order/accounting.js +20 -3
  154. package/dist/modules/order/accounting.js.map +1 -1
  155. package/dist/modules/order/export.d.ts +1 -1
  156. package/dist/modules/order/export.js +1 -1
  157. package/dist/modules/order/grid.d.ts +1 -1
  158. package/dist/modules/order/grid.d.ts.map +1 -1
  159. package/dist/modules/order/grid.js +335 -43
  160. package/dist/modules/order/grid.js.map +1 -1
  161. package/dist/modules/order/grid_reconcile.d.ts +4 -2
  162. package/dist/modules/order/grid_reconcile.d.ts.map +1 -1
  163. package/dist/modules/order/grid_reconcile.js +242 -222
  164. package/dist/modules/order/grid_reconcile.js.map +1 -1
  165. package/dist/modules/order/grid_reconcile_internal.d.ts +11 -1
  166. package/dist/modules/order/grid_reconcile_internal.d.ts.map +1 -1
  167. package/dist/modules/order/grid_reconcile_internal.js +132 -6
  168. package/dist/modules/order/grid_reconcile_internal.js.map +1 -1
  169. package/dist/modules/order/logger.d.ts +23 -1
  170. package/dist/modules/order/logger.d.ts.map +1 -1
  171. package/dist/modules/order/logger.js +60 -17
  172. package/dist/modules/order/logger.js.map +1 -1
  173. package/dist/modules/order/manager.d.ts +68 -14
  174. package/dist/modules/order/manager.d.ts.map +1 -1
  175. package/dist/modules/order/manager.js +281 -52
  176. package/dist/modules/order/manager.js.map +1 -1
  177. package/dist/modules/order/strategy.d.ts.map +1 -1
  178. package/dist/modules/order/strategy.js +25 -8
  179. package/dist/modules/order/strategy.js.map +1 -1
  180. package/dist/modules/order/sync_engine.d.ts.map +1 -1
  181. package/dist/modules/order/sync_engine.js +262 -167
  182. package/dist/modules/order/sync_engine.js.map +1 -1
  183. package/dist/modules/order/utils/math.d.ts +47 -5
  184. package/dist/modules/order/utils/math.d.ts.map +1 -1
  185. package/dist/modules/order/utils/math.js +175 -11
  186. package/dist/modules/order/utils/math.js.map +1 -1
  187. package/dist/modules/order/utils/order.d.ts +16 -15
  188. package/dist/modules/order/utils/order.d.ts.map +1 -1
  189. package/dist/modules/order/utils/order.js +199 -32
  190. package/dist/modules/order/utils/order.js.map +1 -1
  191. package/dist/modules/order/utils/slot.d.ts +8 -0
  192. package/dist/modules/order/utils/slot.d.ts.map +1 -0
  193. package/dist/modules/order/utils/slot.js +16 -0
  194. package/dist/modules/order/utils/slot.js.map +1 -0
  195. package/dist/modules/order/utils/system.d.ts +52 -4
  196. package/dist/modules/order/utils/system.d.ts.map +1 -1
  197. package/dist/modules/order/utils/system.js +109 -16
  198. package/dist/modules/order/utils/system.js.map +1 -1
  199. package/dist/modules/order/utils/validate.d.ts +6 -9
  200. package/dist/modules/order/utils/validate.d.ts.map +1 -1
  201. package/dist/modules/order/utils/validate.js +107 -85
  202. package/dist/modules/order/utils/validate.js.map +1 -1
  203. package/dist/modules/order/working_grid.d.ts +5 -0
  204. package/dist/modules/order/working_grid.d.ts.map +1 -1
  205. package/dist/modules/order/working_grid.js +21 -0
  206. package/dist/modules/order/working_grid.js.map +1 -1
  207. package/dist/modules/paths.d.ts +4 -2
  208. package/dist/modules/paths.d.ts.map +1 -1
  209. package/dist/modules/paths.js +79 -24
  210. package/dist/modules/paths.js.map +1 -1
  211. package/dist/modules/utils/chain_logs.d.ts +11 -0
  212. package/dist/modules/utils/chain_logs.d.ts.map +1 -0
  213. package/dist/modules/utils/chain_logs.js +23 -0
  214. package/dist/modules/utils/chain_logs.js.map +1 -0
  215. package/dist/modules/utils/sanitize_key.d.ts +7 -0
  216. package/dist/modules/utils/sanitize_key.d.ts.map +1 -1
  217. package/dist/modules/utils/sanitize_key.js +15 -0
  218. package/dist/modules/utils/sanitize_key.js.map +1 -1
  219. package/dist/pm2.d.ts +11 -1
  220. package/dist/pm2.d.ts.map +1 -1
  221. package/dist/pm2.js +66 -15
  222. package/dist/pm2.js.map +1 -1
  223. package/dist/scripts/analyze-credit.d.ts +4 -0
  224. package/dist/scripts/analyze-credit.d.ts.map +1 -0
  225. package/dist/scripts/analyze-credit.js +760 -0
  226. package/dist/scripts/analyze-credit.js.map +1 -0
  227. package/dist/scripts/analyze-orders.d.ts +1 -10
  228. package/dist/scripts/analyze-orders.d.ts.map +1 -1
  229. package/dist/scripts/analyze-orders.js +34 -36
  230. package/dist/scripts/analyze-orders.js.map +1 -1
  231. package/dist/scripts/generate_market_adapter_whitelist.d.ts +2 -5
  232. package/dist/scripts/generate_market_adapter_whitelist.d.ts.map +1 -1
  233. package/dist/scripts/generate_market_adapter_whitelist.js +83 -1
  234. package/dist/scripts/generate_market_adapter_whitelist.js.map +1 -1
  235. package/dist/scripts/test-credit-renewal.d.ts.map +1 -1
  236. package/dist/scripts/test-credit-renewal.js +37 -5
  237. package/dist/scripts/test-credit-renewal.js.map +1 -1
  238. package/dist/scripts/tv.d.ts +11 -0
  239. package/dist/scripts/tv.d.ts.map +1 -0
  240. package/dist/scripts/tv.js +357 -0
  241. package/dist/scripts/tv.js.map +1 -0
  242. package/dist/scripts/update.js +77 -10
  243. package/dist/scripts/update.js.map +1 -1
  244. package/dist/unlock.d.ts.map +1 -1
  245. package/dist/unlock.js +20 -8
  246. package/dist/unlock.js.map +1 -1
  247. package/docs/DEXBOT_COMPARISON.md +11 -11
  248. package/docs/EVOLUTION.md +10 -8
  249. package/docs/FUND_MOVEMENT_AND_ACCOUNTING.md +1 -1
  250. package/docs/GRID_RECALCULATION.md +6 -0
  251. package/docs/MPA_CREDIT_USAGE.md +3 -1
  252. package/docs/README.md +2 -2
  253. package/docs/WORKFLOW.md +3 -1
  254. package/market_adapter/README.md +10 -0
  255. package/package.json +3 -1
  256. package/scripts/README.md +16 -0
@@ -14,9 +14,10 @@ import { writeJsonFileAtomic } from './bots_file_lock.js';
14
14
  import { resolveAssetByRef, nowIso } from './order/utils/system.js';
15
15
  import { FEE_PARAMETERS, DEFAULT_TARGET_CR, TIMING, NATIVE_CLIENT } from './constants.js';
16
16
  import { PATHS } from './paths.js';
17
- import { deriveLiquidityPoolTokenValue, ensureDir as ensureDirSync, } from './order/utils/system.js';
17
+ import { deriveLiquidityPoolTokenValue, derivePriceWithBridges, ensureDir as ensureDirSync, } from './order/utils/system.js';
18
18
  const storage = getStorage();
19
19
  import { buildCollateralFallbackPlan, buildDebtFirstCrPlan, positiveOrNull, resolveMinCollateralIncreaseThreshold, resolveTargetCollateralRatio, } from './cr_planner.js';
20
+ import { borrowAmountForCollateral as sharedBorrowAmountForCollateral, collateralValueFromOfferPrice as sharedCollateralValueFromOfferPrice, creditDealFee as sharedCreditDealFee, creditPriceOrientation as sharedCreditPriceOrientation, dailyOfferFeeRate as sharedDailyOfferFeeRate, extractOfferConversionRate as sharedExtractOfferConversionRate, normalizeCollateralMap, requiredCollateralForBorrow as sharedRequiredCollateralForBorrow, } from './credit_pricing.js';
20
21
  import { getErrorMessage } from './utils/errors.js';
21
22
  const CREDIT_FEE_RATE_DENOM = FEE_PARAMETERS.GRAPHENE_FEE_RATE_DENOM;
22
23
  const ZERO_ASSET_ID = NATIVE_CLIENT.CHAIN.CORE_ASSET_ID;
@@ -62,19 +63,6 @@ function toGrapheneCollateralRatio(value) {
62
63
  const scaled = Math.round(numeric * GRAPHENE_COLLATERAL_RATIO_DENOM);
63
64
  return Number.isInteger(scaled) && scaled > 0 && scaled <= 0xffff ? scaled : null;
64
65
  }
65
- function getMapEntries(value) {
66
- if (value instanceof Map)
67
- return Array.from(value.entries());
68
- if (Array.isArray(value)) {
69
- if (value.length > 0 && typeof value[0] === 'object' && !Array.isArray(value[0]) && value[0] !== null && 'key' in value[0] && 'value' in value[0]) {
70
- return value.map((item) => [item.key, item.value]);
71
- }
72
- return value;
73
- }
74
- if (value && typeof value === 'object')
75
- return Object.entries(value);
76
- return [];
77
- }
78
66
  function getPriceQuoteAssetId(price) {
79
67
  return price?.quote?.asset_id || null;
80
68
  }
@@ -115,15 +103,6 @@ function isMaxBorrowAmountError(err) {
115
103
  const message = String(err?.message || err || '');
116
104
  return /would exceed maxBorrowAmount/.test(message) || /exceeds maxBorrowAmountPerOperation/.test(message);
117
105
  }
118
- function normalizeCollateralMap(acceptableCollateral) {
119
- const result = new Map();
120
- for (const [assetId, price] of getMapEntries(acceptableCollateral)) {
121
- if (!assetId || !price)
122
- continue;
123
- result.set(String(assetId), price);
124
- }
125
- return result;
126
- }
127
106
  function resolveAutoRepayValue(value) {
128
107
  if (value === true)
129
108
  return 1;
@@ -724,13 +703,16 @@ class CreditRuntime {
724
703
  }
725
704
  }
726
705
  // Offer map had no usable entry — fall back to pool derivation for LP
727
- // shares. Only attempt when cached is stale to avoid hourly
706
+ // shares, then to universal DEX pricing (direct market, else bridge
707
+ // hops via BTS) so every collateral/debt pair resolves a rate even
708
+ // when the collateral or pool is not part of the credit offer.
709
+ // Only attempt when cached is stale to avoid hourly
728
710
  // deriveLiquidityPoolTokenValue failures when a fresh live-offer rate
729
711
  // would already have returned. Reuses debtAsset/collateralAsset
730
712
  // resolved above.
731
713
  if (!cachedIsFresh) {
732
714
  if (collateralAsset?.for_liquidity_pool && debtAsset?.id) {
733
- const poolRate = await deriveLiquidityPoolTokenValue(BitShares, collateralAsset.id, debtAsset.id).catch((e) => {
715
+ const poolRate = await deriveLiquidityPoolTokenValue(BitShares, collateralAsset.id, debtAsset.id, 'auto', true).catch((e) => {
734
716
  this.log(`credit runtime: pool token rate derivation failed for ${collateralAsset.id}/${debtAsset.id}: ${getErrorMessage(e)}`);
735
717
  return null;
736
718
  });
@@ -742,6 +724,20 @@ class CreditRuntime {
742
724
  return options.includeSource ? { price: poolRate, source: 'pool-derived' } : poolRate;
743
725
  }
744
726
  }
727
+ if (collateralAsset?.id && debtAsset?.id) {
728
+ const bridged = await derivePriceWithBridges(BitShares, collateralAsset.id, debtAsset.id).catch((e) => {
729
+ this.log(`credit runtime: market rate derivation failed for ${collateralAsset.id}/${debtAsset.id}: ${getErrorMessage(e)}`);
730
+ return null;
731
+ });
732
+ if (bridged && Number.isFinite(bridged.rate) && bridged.rate > 0) {
733
+ if (!this.state.positions[posKey])
734
+ this.state.positions[posKey] = {};
735
+ this.state.positions[posKey].creditConversionRate = bridged.rate;
736
+ this.state.positions[posKey].creditConversionRateAt = Date.now();
737
+ const source = bridged.path === 'direct' ? 'market-direct' : `market-${bridged.path}`;
738
+ return options.includeSource ? { price: bridged.rate, source } : bridged.rate;
739
+ }
740
+ }
745
741
  }
746
742
  if (options.includeSource) {
747
743
  return cachedIsFresh
@@ -865,42 +861,29 @@ class CreditRuntime {
865
861
  }
866
862
  }
867
863
  _creditPriceOrientation(collateralPrice, debtAsset, collateralAsset) {
868
- const baseAssetId = String(collateralPrice?.base?.asset_id || '');
869
- const quoteAssetId = String(collateralPrice?.quote?.asset_id || '');
870
- const debtAssetId = String(debtAsset?.id || '');
871
- const collateralAssetId = String(collateralAsset?.id || '');
872
- if (baseAssetId === debtAssetId && quoteAssetId === collateralAssetId)
873
- return 'core';
874
- if (baseAssetId === collateralAssetId && quoteAssetId === debtAssetId)
875
- return 'legacy-reversed';
876
- return 'core';
864
+ return sharedCreditPriceOrientation(String(collateralPrice?.base?.asset_id || ''), String(collateralPrice?.quote?.asset_id || ''), String(debtAsset?.id || ''), String(collateralAsset?.id || ''));
865
+ }
866
+ _precisionOfPair(debtAsset, collateralAsset) {
867
+ return (assetId) => {
868
+ if (debtAsset && String(assetId) === String(debtAsset.id))
869
+ return getAssetPrecision(debtAsset);
870
+ if (collateralAsset && String(assetId) === String(collateralAsset.id))
871
+ return getAssetPrecision(collateralAsset);
872
+ return null;
873
+ };
877
874
  }
878
875
  _extractRateFromCollateralMap(collateralMap, collateralAssetId, debtAsset, collateralAsset) {
879
- const price = collateralMap.get(collateralAssetId);
880
- if (!price)
881
- return null;
882
- const orientation = this._creditPriceOrientation(price, debtAsset, collateralAsset);
883
- const baseAmount = blockchainAmountToFloat(price?.base, orientation === 'legacy-reversed' ? collateralAsset : debtAsset);
884
- const quoteAmount = blockchainAmountToFloat(price?.quote, orientation === 'legacy-reversed' ? debtAsset : collateralAsset);
885
- if (baseAmount == null || quoteAmount == null || baseAmount <= 0)
886
- return null;
887
- const rate = orientation === 'legacy-reversed'
888
- ? quoteAmount / baseAmount
889
- : baseAmount / quoteAmount;
890
- if (!Number.isFinite(rate) || rate <= 0)
891
- return null;
876
+ const rate = sharedExtractOfferConversionRate(collateralMap, String(collateralAssetId), String(debtAsset?.id || ''), this._precisionOfPair(debtAsset, collateralAsset));
877
+ // The offer lists this collateral but the price is unusable (missing
878
+ // asset precision or invalid base/quote amounts) — log it, otherwise
879
+ // the null is indistinguishable from "not listed" downstream.
880
+ if (rate === null && collateralMap?.get(String(collateralAssetId)) != null) {
881
+ this.log(`credit runtime: offer lists ${collateralAssetId} but its price cannot be resolved (missing precision or invalid base/quote amounts)`);
882
+ }
892
883
  return rate;
893
884
  }
894
885
  _calculateBorrowAmountFromCollateral(collateralAmountInt, collateralPrice, debtAsset = null, collateralAsset = null) {
895
- const baseAmount = toFiniteNumber(collateralPrice?.base?.amount, undefined);
896
- const quoteAmount = toFiniteNumber(collateralPrice?.quote?.amount, undefined);
897
- if (!Number.isFinite(baseAmount) || !Number.isFinite(quoteAmount) || baseAmount <= 0 || quoteAmount <= 0) {
898
- return null;
899
- }
900
- if (this._creditPriceOrientation(collateralPrice, debtAsset, collateralAsset) === 'legacy-reversed') {
901
- return Math.floor((Number(collateralAmountInt) * quoteAmount) / baseAmount);
902
- }
903
- return Math.floor((Number(collateralAmountInt) * baseAmount) / quoteAmount);
886
+ return sharedBorrowAmountForCollateral(collateralAmountInt, collateralPrice, debtAsset?.id != null ? String(debtAsset.id) : null, collateralAsset?.id != null ? String(collateralAsset.id) : null);
904
887
  }
905
888
  _enforceMaxBorrowAmount(policy, borrowInt, debtAsset, options = {}) {
906
889
  const maxBorrowAmountValue = positiveOrNull(policy?.maxBorrowAmount);
@@ -1002,14 +985,8 @@ class CreditRuntime {
1002
985
  }
1003
986
  }
1004
987
  _calculateDailyFeeRate(offer) {
1005
- const feeRate = toFiniteNumber(offer?.fee_rate, 0) || 0;
1006
- const maxDurationSeconds = toFiniteNumber(offer?.max_duration_seconds, 0) || 0;
1007
- if (feeRate <= 0 || maxDurationSeconds <= 0)
1008
- return 0;
1009
988
  const feeRateDenom = this.bot?.config?.feeParams?.GRAPHENE_FEE_RATE_DENOM ?? FEE_PARAMETERS.GRAPHENE_FEE_RATE_DENOM;
1010
- const flatFeePercent = feeRate / feeRateDenom;
1011
- const durationDays = maxDurationSeconds / 86400;
1012
- return flatFeePercent / durationDays;
989
+ return sharedDailyOfferFeeRate(offer, feeRateDenom);
1013
990
  }
1014
991
  _getDefaultMaxFeeRatePerDay() {
1015
992
  return this.bot?.config?.feeParams?.DEFAULT_MAX_FEE_RATE_PER_DAY ?? FEE_PARAMETERS.DEFAULT_MAX_FEE_RATE_PER_DAY;
@@ -1046,43 +1023,21 @@ class CreditRuntime {
1046
1023
  return { allow: true, reason: null };
1047
1024
  }
1048
1025
  async _calculateCollateralValueInDebtAsset(collateralAmountInt, collateralAsset, debtAsset, collateralPrice) {
1049
- const collateralAmountFloat = blockchainToFloat(collateralAmountInt, collateralAsset.precision);
1050
- if (!Number.isFinite(collateralAmountFloat) || collateralAmountFloat <= 0) {
1051
- return null;
1052
- }
1053
1026
  if (collateralAsset?.for_liquidity_pool) {
1054
- const valuePerShare = await deriveLiquidityPoolTokenValue(BitShares, collateralAsset.id, debtAsset.id);
1027
+ const collateralAmountFloat = blockchainToFloat(collateralAmountInt, collateralAsset.precision);
1028
+ if (!Number.isFinite(collateralAmountFloat) || collateralAmountFloat <= 0) {
1029
+ return null;
1030
+ }
1031
+ const valuePerShare = await deriveLiquidityPoolTokenValue(BitShares, collateralAsset.id, debtAsset.id, 'auto', true);
1055
1032
  if (valuePerShare == null || !Number.isFinite(valuePerShare) || valuePerShare <= 0) {
1056
1033
  return null;
1057
1034
  }
1058
1035
  return collateralAmountFloat * valuePerShare;
1059
1036
  }
1060
- const orientation = this._creditPriceOrientation(collateralPrice, debtAsset, collateralAsset);
1061
- const baseAmountFloat = blockchainAmountToFloat(collateralPrice?.base, orientation === 'legacy-reversed' ? collateralAsset : debtAsset);
1062
- const quoteAmountFloat = blockchainAmountToFloat(collateralPrice?.quote, orientation === 'legacy-reversed' ? debtAsset : collateralAsset);
1063
- if (baseAmountFloat == null || quoteAmountFloat == null || baseAmountFloat <= 0 || quoteAmountFloat <= 0) {
1064
- return null;
1065
- }
1066
- if (orientation === 'legacy-reversed') {
1067
- return (collateralAmountFloat * quoteAmountFloat) / baseAmountFloat;
1068
- }
1069
- return (collateralAmountFloat * baseAmountFloat) / quoteAmountFloat;
1037
+ return this._calculateCreditOfferCollateralValueInDebtAsset(collateralAmountInt, collateralAsset, debtAsset, collateralPrice);
1070
1038
  }
1071
1039
  _calculateCreditOfferCollateralValueInDebtAsset(collateralAmountInt, collateralAsset, debtAsset, collateralPrice) {
1072
- const collateralAmountFloat = blockchainToFloat(collateralAmountInt, collateralAsset.precision);
1073
- if (!Number.isFinite(collateralAmountFloat) || collateralAmountFloat <= 0) {
1074
- return null;
1075
- }
1076
- const orientation = this._creditPriceOrientation(collateralPrice, debtAsset, collateralAsset);
1077
- const baseAmountFloat = blockchainAmountToFloat(collateralPrice?.base, orientation === 'legacy-reversed' ? collateralAsset : debtAsset);
1078
- const quoteAmountFloat = blockchainAmountToFloat(collateralPrice?.quote, orientation === 'legacy-reversed' ? debtAsset : collateralAsset);
1079
- if (baseAmountFloat == null || quoteAmountFloat == null || baseAmountFloat <= 0 || quoteAmountFloat <= 0) {
1080
- return null;
1081
- }
1082
- if (orientation === 'legacy-reversed') {
1083
- return (collateralAmountFloat * quoteAmountFloat) / baseAmountFloat;
1084
- }
1085
- return (collateralAmountFloat * baseAmountFloat) / quoteAmountFloat;
1040
+ return sharedCollateralValueFromOfferPrice(collateralAmountInt, collateralAsset?.precision, collateralPrice, String(debtAsset?.id || ''), String(collateralAsset?.id || ''), this._precisionOfPair(debtAsset, collateralAsset));
1086
1041
  }
1087
1042
  async _fetchBorrowerDeals() {
1088
1043
  if (this._borrowerDealsCache !== null)
@@ -1677,23 +1632,10 @@ class CreditRuntime {
1677
1632
  return op;
1678
1633
  }
1679
1634
  _calculateRequiredCollateral(borrowAmountInt, collateralPrice, debtAsset = null, collateralAsset = null) {
1680
- const baseAmount = toFiniteNumber(collateralPrice?.base?.amount, undefined);
1681
- const quoteAmount = toFiniteNumber(collateralPrice?.quote?.amount, undefined);
1682
- if (!Number.isFinite(baseAmount) || !Number.isFinite(quoteAmount) || baseAmount <= 0 || quoteAmount <= 0) {
1683
- return null;
1684
- }
1685
- if (this._creditPriceOrientation(collateralPrice, debtAsset, collateralAsset) === 'legacy-reversed') {
1686
- return Math.ceil((Number(borrowAmountInt) * baseAmount) / quoteAmount);
1687
- }
1688
- return Math.ceil((Number(borrowAmountInt) * quoteAmount) / baseAmount);
1635
+ return sharedRequiredCollateralForBorrow(borrowAmountInt, collateralPrice, debtAsset?.id != null ? String(debtAsset.id) : null, collateralAsset?.id != null ? String(collateralAsset.id) : null);
1689
1636
  }
1690
1637
  _calculateCreditFee(repayAmountInt, feeRate) {
1691
- const repay = BigInt(Math.max(0, Math.trunc(Number(repayAmountInt))));
1692
- const rate = BigInt(Math.max(0, Math.trunc(Number(feeRate))));
1693
- const denom = BigInt(CREDIT_FEE_RATE_DENOM);
1694
- if (repay <= 0n || rate <= 0n)
1695
- return 0;
1696
- return Number(((repay * rate) + denom - 1n) / denom);
1638
+ return sharedCreditDealFee(repayAmountInt, feeRate, CREDIT_FEE_RATE_DENOM);
1697
1639
  }
1698
1640
  async buildCreditDealRepayOperation(deal, repayAmount) {
1699
1641
  const dealSummary = typeof deal === 'object' ? parseDealSummary(deal) : null;