dexbot 1.4.20 → 1.4.21

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 (234) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +22 -12
  3. package/analysis/ama_fitting/calibrate_convergence_er.ts +1 -1
  4. package/analysis/ama_fitting/package.json +1 -1
  5. package/analysis/bot_fitting/shared_utils.ts +1 -1
  6. package/analysis/bot_key_utils.ts +1 -5
  7. package/analysis/bot_usage/kibana_bot_queries.ts +1 -256
  8. package/analysis/chart_css.ts +1 -1
  9. package/analysis/math_utils.ts +1 -8
  10. package/analysis/trend_detection/package.json +1 -1
  11. package/claw/ecosystem.config.cjs +2 -3
  12. package/claw/examples/memu_integration_example.ts +17 -17
  13. package/claw/modules/chain_actions.ts +51 -54
  14. package/claw/modules/chain_broadcast.ts +66 -104
  15. package/claw/modules/claw_bridge.ts +60 -80
  16. package/claw/modules/claw_catalog.ts +47 -16
  17. package/claw/modules/claw_infra.ts +1 -5
  18. package/claw/modules/claw_launcher.ts +47 -49
  19. package/claw/modules/claw_skill_md.ts +8 -11
  20. package/claw/modules/credit_runtime_adapter.ts +2 -18
  21. package/claw/modules/decision_loop.ts +4 -0
  22. package/claw/modules/dexbot_bridge.ts +1 -1
  23. package/claw/modules/dexbot_profiles.ts +5 -21
  24. package/claw/modules/honest_ecosystem.ts +24 -8
  25. package/claw/modules/liquidity_pools.ts +10 -3
  26. package/claw/modules/mcp_utils.ts +109 -0
  27. package/claw/modules/memu_bridge.ts +76 -54
  28. package/claw/modules/mpa_utils.ts +26 -3
  29. package/claw/modules/position_discovery.ts +16 -27
  30. package/claw/modules/position_manager.ts +32 -41
  31. package/claw/modules/position_manager_watch.ts +3 -2
  32. package/claw/modules/short_mpa_strategy.ts +1 -9
  33. package/claw/modules/skill_utils.ts +5 -3
  34. package/claw/modules/utils.ts +9 -1
  35. package/claw/package.json +1 -1
  36. package/claw/runtimes/openclaw-plugin/index.ts +27 -10
  37. package/claw/runtimes/openclaw-plugin/openclaw.plugin.json +1 -1
  38. package/claw/runtimes/openclaw-plugin/package.json +1 -1
  39. package/claw/scripts/claw_bridge.ts +1 -1
  40. package/claw/scripts/claw_mcp_server.ts +19 -78
  41. package/claw/scripts/honest_assets_report.ts +19 -84
  42. package/claw/scripts/memu_mcp_server.ts +57 -155
  43. package/claw/tests/test_claw_bridge.ts +6 -2
  44. package/claw/tests/test_claw_mcp_transport.ts +2 -2
  45. package/dist/analysis/ama_fitting/calibrate_convergence_er.js +1 -1
  46. package/dist/analysis/ama_fitting/calibrate_convergence_er.js.map +1 -1
  47. package/dist/analysis/bot_fitting/shared_utils.d.ts +1 -12
  48. package/dist/analysis/bot_fitting/shared_utils.d.ts.map +1 -1
  49. package/dist/analysis/bot_fitting/shared_utils.js +1 -1
  50. package/dist/analysis/bot_fitting/shared_utils.js.map +1 -1
  51. package/dist/analysis/bot_key_utils.d.ts +1 -1
  52. package/dist/analysis/bot_key_utils.d.ts.map +1 -1
  53. package/dist/analysis/bot_key_utils.js +1 -5
  54. package/dist/analysis/bot_key_utils.js.map +1 -1
  55. package/dist/analysis/bot_usage/kibana_bot_queries.d.ts +1 -337
  56. package/dist/analysis/bot_usage/kibana_bot_queries.d.ts.map +1 -1
  57. package/dist/analysis/bot_usage/kibana_bot_queries.js +1 -241
  58. package/dist/analysis/bot_usage/kibana_bot_queries.js.map +1 -1
  59. package/dist/analysis/chart_css.d.ts +1 -15
  60. package/dist/analysis/chart_css.d.ts.map +1 -1
  61. package/dist/analysis/chart_css.js +1 -1
  62. package/dist/analysis/chart_css.js.map +1 -1
  63. package/dist/analysis/math_utils.d.ts +3 -5
  64. package/dist/analysis/math_utils.d.ts.map +1 -1
  65. package/dist/analysis/math_utils.js +3 -5
  66. package/dist/analysis/math_utils.js.map +1 -1
  67. package/dist/bot.js +2 -2
  68. package/dist/bot.js.map +1 -1
  69. package/dist/credential-daemon.js +1 -1
  70. package/dist/credential-daemon.js.map +1 -1
  71. package/dist/dexbot.d.ts.map +1 -1
  72. package/dist/dexbot.js +18 -14
  73. package/dist/dexbot.js.map +1 -1
  74. package/dist/market_adapter/ama_signal_runner.js +3 -3
  75. package/dist/market_adapter/core/kibana_client.d.ts +1 -3
  76. package/dist/market_adapter/core/kibana_client.d.ts.map +1 -1
  77. package/dist/market_adapter/core/kibana_client.js +1 -1
  78. package/dist/market_adapter/core/kibana_client.js.map +1 -1
  79. package/dist/market_adapter/core/market_adapter_service.d.ts +1 -2
  80. package/dist/market_adapter/core/market_adapter_service.d.ts.map +1 -1
  81. package/dist/market_adapter/core/market_adapter_service.js +1 -1
  82. package/dist/market_adapter/core/market_adapter_service.js.map +1 -1
  83. package/dist/market_adapter/core/strategies/regime_gate.d.ts +1 -2
  84. package/dist/market_adapter/core/strategies/regime_gate.d.ts.map +1 -1
  85. package/dist/market_adapter/core/strategies/regime_gate.js +1 -1
  86. package/dist/market_adapter/core/strategies/regime_gate.js.map +1 -1
  87. package/dist/market_adapter/inputs/fetch_cex_synthetic_data.js +2 -2
  88. package/dist/market_adapter/inputs/fetch_cex_synthetic_data.js.map +1 -1
  89. package/dist/market_adapter/inputs/fetch_lp_data.d.ts +5 -5
  90. package/dist/market_adapter/inputs/fetch_lp_data.js +5 -5
  91. package/dist/market_adapter/inputs/kibana_source.d.ts +1 -2
  92. package/dist/market_adapter/inputs/kibana_source.d.ts.map +1 -1
  93. package/dist/market_adapter/inputs/kibana_source.js +1 -1
  94. package/dist/market_adapter/inputs/kibana_source.js.map +1 -1
  95. package/dist/market_adapter/lp_chart_strategy_loader.d.ts +1 -2
  96. package/dist/market_adapter/lp_chart_strategy_loader.d.ts.map +1 -1
  97. package/dist/market_adapter/lp_chart_strategy_loader.js +4 -4
  98. package/dist/market_adapter/lp_chart_strategy_loader.js.map +1 -1
  99. package/dist/market_adapter/market_adapter.d.ts.map +1 -1
  100. package/dist/market_adapter/market_adapter.js +2 -1
  101. package/dist/market_adapter/market_adapter.js.map +1 -1
  102. package/dist/modules/account_bots.d.ts +3 -0
  103. package/dist/modules/account_bots.d.ts.map +1 -1
  104. package/dist/modules/account_bots.js +156 -46
  105. package/dist/modules/account_bots.js.map +1 -1
  106. package/dist/modules/account_orders.d.ts +1 -7
  107. package/dist/modules/account_orders.d.ts.map +1 -1
  108. package/dist/modules/account_orders.js +9 -17
  109. package/dist/modules/account_orders.js.map +1 -1
  110. package/dist/modules/bitshares_client.d.ts +2 -14
  111. package/dist/modules/bitshares_client.d.ts.map +1 -1
  112. package/dist/modules/bitshares_client.js +22 -31
  113. package/dist/modules/bitshares_client.js.map +1 -1
  114. package/dist/modules/bot_settings.js +1 -1
  115. package/dist/modules/bot_settings.js.map +1 -1
  116. package/dist/modules/chain_keys.js +2 -2
  117. package/dist/modules/chain_keys.js.map +1 -1
  118. package/dist/modules/chain_orders.d.ts +2 -3
  119. package/dist/modules/chain_orders.d.ts.map +1 -1
  120. package/dist/modules/chain_orders.js +8 -25
  121. package/dist/modules/chain_orders.js.map +1 -1
  122. package/dist/modules/config.d.ts.map +1 -1
  123. package/dist/modules/config.js +4 -1
  124. package/dist/modules/config.js.map +1 -1
  125. package/dist/modules/constants.d.ts +0 -1
  126. package/dist/modules/constants.d.ts.map +1 -1
  127. package/dist/modules/constants.js +0 -4
  128. package/dist/modules/constants.js.map +1 -1
  129. package/dist/modules/credential_policy.js +1 -1
  130. package/dist/modules/credential_policy.js.map +1 -1
  131. package/dist/modules/dexbot_class.d.ts.map +1 -1
  132. package/dist/modules/dexbot_class.js +3 -2
  133. package/dist/modules/dexbot_class.js.map +1 -1
  134. package/dist/modules/dexbot_state_recovery.d.ts.map +1 -1
  135. package/dist/modules/dexbot_state_recovery.js +2 -1
  136. package/dist/modules/dexbot_state_recovery.js.map +1 -1
  137. package/dist/modules/fund_registry.d.ts.map +1 -1
  138. package/dist/modules/fund_registry.js +5 -2
  139. package/dist/modules/fund_registry.js.map +1 -1
  140. package/dist/modules/launcher/bot_supervisor.d.ts.map +1 -1
  141. package/dist/modules/launcher/bot_supervisor.js +6 -7
  142. package/dist/modules/launcher/bot_supervisor.js.map +1 -1
  143. package/dist/modules/launcher/foreign_cred_daemon.d.ts.map +1 -1
  144. package/dist/modules/launcher/foreign_cred_daemon.js +6 -0
  145. package/dist/modules/launcher/foreign_cred_daemon.js.map +1 -1
  146. package/dist/modules/launcher/market_adapter_runtime.d.ts +2 -3
  147. package/dist/modules/launcher/market_adapter_runtime.d.ts.map +1 -1
  148. package/dist/modules/launcher/market_adapter_runtime.js +7 -15
  149. package/dist/modules/launcher/market_adapter_runtime.js.map +1 -1
  150. package/dist/modules/launcher/monolithic_runtime.d.ts.map +1 -1
  151. package/dist/modules/launcher/monolithic_runtime.js +1 -0
  152. package/dist/modules/launcher/monolithic_runtime.js.map +1 -1
  153. package/dist/modules/launcher/status_reporting.d.ts +1 -2
  154. package/dist/modules/launcher/status_reporting.d.ts.map +1 -1
  155. package/dist/modules/launcher/status_reporting.js +1 -4
  156. package/dist/modules/launcher/status_reporting.js.map +1 -1
  157. package/dist/modules/order/accounting.js +2 -2
  158. package/dist/modules/order/accounting.js.map +1 -1
  159. package/dist/modules/order/format.d.ts +0 -8
  160. package/dist/modules/order/format.d.ts.map +1 -1
  161. package/dist/modules/order/format.js +0 -8
  162. package/dist/modules/order/format.js.map +1 -1
  163. package/dist/modules/order/logger.js +1 -1
  164. package/dist/modules/order/logger.js.map +1 -1
  165. package/dist/modules/order/logger_state.d.ts +1 -13
  166. package/dist/modules/order/logger_state.d.ts.map +1 -1
  167. package/dist/modules/order/logger_state.js +1 -11
  168. package/dist/modules/order/logger_state.js.map +1 -1
  169. package/dist/modules/order/processed_fill_store.d.ts +0 -5
  170. package/dist/modules/order/processed_fill_store.d.ts.map +1 -1
  171. package/dist/modules/order/processed_fill_store.js +1 -12
  172. package/dist/modules/order/processed_fill_store.js.map +1 -1
  173. package/dist/modules/order/sync_engine.d.ts.map +1 -1
  174. package/dist/modules/order/sync_engine.js +10 -3
  175. package/dist/modules/order/sync_engine.js.map +1 -1
  176. package/dist/modules/order/utils/math.d.ts +7 -1
  177. package/dist/modules/order/utils/math.d.ts.map +1 -1
  178. package/dist/modules/order/utils/math.js +19 -1
  179. package/dist/modules/order/utils/math.js.map +1 -1
  180. package/dist/modules/order/utils/order.d.ts.map +1 -1
  181. package/dist/modules/order/utils/order.js +10 -2
  182. package/dist/modules/order/utils/order.js.map +1 -1
  183. package/dist/modules/runtime_settings.js +3 -1
  184. package/dist/modules/runtime_settings.js.map +1 -1
  185. package/dist/modules/settings_merge.d.ts.map +1 -1
  186. package/dist/modules/settings_merge.js +3 -1
  187. package/dist/modules/settings_merge.js.map +1 -1
  188. package/dist/modules/storage/browser_adapter.d.ts +8 -3
  189. package/dist/modules/storage/browser_adapter.d.ts.map +1 -1
  190. package/dist/modules/storage/browser_adapter.js +53 -4
  191. package/dist/modules/storage/browser_adapter.js.map +1 -1
  192. package/dist/modules/utils/sanitize_key.d.ts +7 -0
  193. package/dist/modules/utils/sanitize_key.d.ts.map +1 -0
  194. package/dist/modules/utils/sanitize_key.js +15 -0
  195. package/dist/modules/utils/sanitize_key.js.map +1 -0
  196. package/dist/pm2.js +6 -6
  197. package/dist/pm2.js.map +1 -1
  198. package/dist/scripts/analyze-orders.d.ts +2 -2
  199. package/dist/scripts/analyze-orders.d.ts.map +1 -1
  200. package/dist/scripts/analyze-orders.js +4 -12
  201. package/dist/scripts/analyze-orders.js.map +1 -1
  202. package/dist/scripts/runner.js +1 -1
  203. package/dist/scripts/runner.js.map +1 -1
  204. package/dist/scripts/update.js +1 -1
  205. package/dist/scripts/update.js.map +1 -1
  206. package/docs/BITSHARES_ONBOARDING.md +63 -18
  207. package/docs/COPY_ON_WRITE_MASTER_PLAN.md +5 -14
  208. package/docs/COW_INVARIANTS.md +4 -4
  209. package/docs/CREDENTIAL_SECURITY.md +0 -11
  210. package/docs/DEXBOT_COMPARISON.md +11 -11
  211. package/docs/EVOLUTION.md +11 -10
  212. package/docs/FUND_MOVEMENT_AND_ACCOUNTING.md +27 -83
  213. package/docs/GRID_RECALCULATION.md +1 -13
  214. package/docs/GRID_RECONCILE.md +24 -24
  215. package/docs/LIFECYCLE.md +4 -4
  216. package/docs/LOGGING.md +1 -1
  217. package/docs/MPA_CREDIT_USAGE.md +3 -3
  218. package/docs/README.md +2 -2
  219. package/docs/WORKFLOW.md +2 -2
  220. package/docs/architecture.md +43 -38
  221. package/docs/developer_guide.md +16 -18
  222. package/market_adapter/README.md +0 -2
  223. package/modules/README.md +2 -1
  224. package/package.json +1 -1
  225. package/scripts/README.md +1 -1
  226. package/claw/openclaw.plugin.json +0 -13
  227. package/dist/market_adapter/merge_lp_data.d.ts +0 -3
  228. package/dist/market_adapter/merge_lp_data.d.ts.map +0 -1
  229. package/dist/market_adapter/merge_lp_data.js +0 -125
  230. package/dist/market_adapter/merge_lp_data.js.map +0 -1
  231. package/dist/market_adapter/utils/paths.d.ts +0 -3
  232. package/dist/market_adapter/utils/paths.d.ts.map +0 -1
  233. package/dist/market_adapter/utils/paths.js +0 -5
  234. package/dist/market_adapter/utils/paths.js.map +0 -1
@@ -3,6 +3,8 @@
3
3
  import definePluginEntry from 'openclaw/plugin-sdk/plugin-entry';
4
4
  import { getClawToolCatalog } from '../../modules/claw_catalog.js';
5
5
  import { runClawCommand } from '../../modules/claw_bridge.js';
6
+ import { getErrorMessage } from '../../../modules/utils/errors.js';
7
+
6
8
  function formatResult(result: any) {
7
9
  return JSON.stringify(result, null, 2);
8
10
  }
@@ -18,16 +20,31 @@ const plugin = definePluginEntry({
18
20
  description: `[${tool.risk}] ${tool.description}`,
19
21
  parameters: tool.inputSchema,
20
22
  async execute(_id: any, params: any) {
21
- const result = await runClawCommand(tool.command, { ...params, runtimeName: 'openclaw' });
22
- return {
23
- content: [
24
- {
25
- type: "text",
26
- text: formatResult(result)
27
- }
28
- ],
29
- structuredContent: result
30
- };
23
+ // Match the MCP servers' convention: tool failures surface as an
24
+ // isError result instead of a raw rejected promise.
25
+ try {
26
+ const result = await runClawCommand(tool.command, { ...params, runtimeName: 'openclaw' });
27
+ return {
28
+ content: [
29
+ {
30
+ type: "text",
31
+ text: formatResult(result)
32
+ }
33
+ ],
34
+ structuredContent: result
35
+ };
36
+ } catch (error: any) {
37
+ const text = error && error.stack ? error.stack : getErrorMessage(error);
38
+ return {
39
+ content: [
40
+ {
41
+ type: "text",
42
+ text
43
+ }
44
+ ],
45
+ isError: true
46
+ };
47
+ }
31
48
  }
32
49
  });
33
50
  }
@@ -2,7 +2,7 @@
2
2
  "id": "bitshares-claw",
3
3
  "name": "BitShares Claw",
4
4
  "description": "Native BitShares and DEXBot2 tools from the DEXBot2 claw integration",
5
- "version": "1.4.20",
5
+ "version": "1.4.21",
6
6
  "skills": [
7
7
  "skills"
8
8
  ],
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "bitshares-claw-openclaw-plugin",
3
3
  "private": true,
4
- "version": "1.4.20",
4
+ "version": "1.4.21",
5
5
  "type": "module",
6
6
  "main": "index.js"
7
7
  }
@@ -154,5 +154,5 @@ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href)
154
154
  });
155
155
  }
156
156
 
157
- export { describeScriptRuntimeManifest as describeRuntimeManifest, main }
157
+ export { describeScriptRuntimeManifest as describeRuntimeManifest }
158
158
 
@@ -6,7 +6,7 @@
6
6
  // console shim has been installed. Static imports here are limited to the
7
7
  // lightweight transport helpers (mcp_utils) which never write to stdout.
8
8
 
9
- import { success, failure, runMcpServer, createMessageParser } from '../modules/mcp_utils.js';
9
+ import { createJsonRpcToolsHandler, jsonRpcError, runMcpServer, createMessageParser } from '../modules/mcp_utils.js';
10
10
  import { pathToFileURL } from 'node:url';
11
11
 
12
12
  console.log = () => {};
@@ -59,84 +59,26 @@ async function listMcpTools() {
59
59
  }));
60
60
  }
61
61
 
62
- async function handleRequest(message: any, defaults: any) {
63
- const { id, method, params } = message;
64
-
65
- switch (method) {
66
- case 'initialize':
67
- return success(id, {
68
- // Echo the client's requested protocol version when provided, so a
69
- // JSONL-speaking client can negotiate its own version.
70
- protocolVersion: params?.protocolVersion || '2024-11-05',
71
- capabilities: {
72
- tools: {
73
- listChanged: false
74
- }
75
- },
76
- serverInfo: {
77
- name: 'bitshares-claw',
78
- version: '0.1.0'
79
- }
80
- });
81
-
82
- case 'notifications/initialized':
83
- return;
84
-
85
- case 'ping':
86
- return success(id, {});
87
-
88
- case 'tools/list':
89
- try {
90
- return success(id, {
91
- tools: await listMcpTools()
92
- });
93
- } catch (error: any) {
94
- return failure(id, -32602, `Failed to load tool catalog: ${error && error.message ? error.message : String(error)}`);
95
- }
96
-
97
- case 'tools/call': {
98
- try {
99
- const { getClawToolByName } = await import('../modules/claw_catalog.js');
100
- const tool = getClawToolByName(params?.name);
101
- if (!tool) {
102
- return failure(id, -32602, `Unknown tool: ${params?.name || '(missing)'}`);
103
- }
104
-
105
- const { runClawCommand } = await import('../modules/claw_bridge.js');
106
- const result = await runClawCommand(tool.command, {
107
- ...defaults,
108
- ...(params?.arguments || {})
109
- });
110
-
111
- return success(id, {
112
- content: [
113
- {
114
- type: 'text',
115
- text: JSON.stringify(result, null, 2)
116
- }
117
- ],
118
- structuredContent: result
119
- });
120
- } catch (error: any) {
121
- return success(id, {
122
- content: [
123
- {
124
- type: 'text',
125
- text: error && error.stack ? error.stack : String(error)
126
- }
127
- ],
128
- isError: true
129
- });
130
- }
131
- }
132
-
133
- default:
134
- if (id !== undefined) {
135
- return failure(id, -32601, `Method not found: ${method}`);
136
- }
62
+ async function callTool(params: any, defaults: any) {
63
+ const { getClawToolByName } = await import('../modules/claw_catalog.js');
64
+ const tool = getClawToolByName(params?.name);
65
+ if (!tool) {
66
+ throw jsonRpcError(-32602, `Unknown tool: ${params?.name || '(missing)'}`);
137
67
  }
68
+
69
+ const { runClawCommand } = await import('../modules/claw_bridge.js');
70
+ return runClawCommand(tool.command, {
71
+ ...defaults,
72
+ ...(params?.arguments || {})
73
+ });
138
74
  }
139
75
 
76
+ const handleRequest = createJsonRpcToolsHandler({
77
+ serverName: 'bitshares-claw',
78
+ listTools: listMcpTools,
79
+ callTool
80
+ });
81
+
140
82
  if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
141
83
  runMcpServer(parseArgs, handleRequest).catch((err: unknown) => {
142
84
  process.stderr.write(`${err instanceof Error && err.stack ? err.stack : String(err)}\n`);
@@ -144,5 +86,4 @@ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href)
144
86
  });
145
87
  }
146
88
 
147
- export { createMessageParser, failure, handleRequest, listMcpTools, success }
148
-
89
+ export { createMessageParser, handleRequest }
@@ -1,5 +1,5 @@
1
- import { getAsset, getBackingAsset, getBitassetData, getCallOrders, getDynamicGlobalProperties, listAssets } from '../modules/chain_queries.js';
2
- import { getHardcodedHonestMoneyBridge } from '../modules/honest_ecosystem.js';
1
+ import { getAsset, getBackingAsset, getBitassetData, getCallOrders, getDynamicGlobalProperties } from '../modules/chain_queries.js';
2
+ import { getHonestMoneyBridge, isMpa, paginateListAssets } from '../modules/honest_ecosystem.js';
3
3
  import { getErrorMessage } from '../../modules/utils/errors.js';
4
4
 
5
5
  const DEFAULT_BATCH_SIZE = 100;
@@ -49,67 +49,17 @@ function toPositiveInteger(value: any, fallback: any) {
49
49
  return Number.isInteger(value) && value > 0 ? value : fallback;
50
50
  }
51
51
 
52
- function isMpa(asset: any) {
53
- return Boolean(asset && asset.bitasset_data_id);
54
- }
55
-
56
- function isHonestAsset(asset: any) {
57
- return typeof asset?.symbol === 'string' && asset.symbol.startsWith('HONEST.');
58
- }
59
-
60
52
  async function fetchAllAssets({ batchSize, maxPages, startSymbol }: { batchSize: any; maxPages: any; startSymbol: any }) {
61
- const results = [];
62
- let lowerBound = startSymbol;
63
- let previousLastSymbol = null;
64
-
65
- for (let page = 0; page < maxPages; page += 1) {
66
- const batch = await listAssets(lowerBound, batchSize);
67
- if (!Array.isArray(batch) || batch.length === 0) {
68
- break;
69
- }
70
-
71
- let pageItems = batch.filter(Boolean);
72
- if (previousLastSymbol && pageItems[0]?.symbol === previousLastSymbol) {
73
- pageItems = pageItems.slice(1);
74
- }
75
-
76
- if (pageItems.length === 0) {
77
- break;
78
- }
79
-
53
+ const results: any[] = [];
54
+ await paginateListAssets({ batchSize, maxPages, startSymbol }, (pageItems) => {
80
55
  results.push(...pageItems);
81
- previousLastSymbol = pageItems[pageItems.length - 1].symbol;
82
- lowerBound = previousLastSymbol;
83
-
84
- if (batch.length < batchSize) {
85
- break;
86
- }
87
- }
88
-
56
+ });
89
57
  return results;
90
58
  }
91
59
 
92
60
  async function fetchAssetsByPrefix({ batchSize, maxPages, prefix, startSymbol }: { batchSize: any; maxPages: any; prefix: any; startSymbol: any }) {
93
- const results = [];
94
- let lowerBound = startSymbol;
95
- let previousLastSymbol = null;
96
-
97
- for (let page = 0; page < maxPages; page += 1) {
98
- const batch = await listAssets(lowerBound, batchSize);
99
- if (!Array.isArray(batch) || batch.length === 0) {
100
- break;
101
- }
102
-
103
- let pageItems = batch.filter(Boolean);
104
- if (previousLastSymbol && pageItems[0]?.symbol === previousLastSymbol) {
105
- pageItems = pageItems.slice(1);
106
- }
107
-
108
- if (pageItems.length === 0) {
109
- break;
110
- }
111
-
112
- const matching = [];
61
+ const matching: any[] = [];
62
+ await paginateListAssets({ batchSize, maxPages, startSymbol }, (pageItems) => {
113
63
  let crossedPrefixBoundary = false;
114
64
 
115
65
  for (const item of pageItems) {
@@ -125,18 +75,10 @@ async function fetchAssetsByPrefix({ batchSize, maxPages, prefix, startSymbol }:
125
75
  }
126
76
  }
127
77
 
128
- results.push(...matching);
129
-
130
- const lastItem = pageItems[pageItems.length - 1];
131
- previousLastSymbol = lastItem?.symbol || previousLastSymbol;
132
- lowerBound = previousLastSymbol || lowerBound;
133
-
134
- if (crossedPrefixBoundary || batch.length < batchSize) {
135
- break;
136
- }
137
- }
78
+ return !crossedPrefixBoundary;
79
+ });
138
80
 
139
- return results;
81
+ return matching;
140
82
  }
141
83
 
142
84
  async function mapWithConcurrency(items: any, concurrency: any, mapper: any) {
@@ -179,16 +121,14 @@ function computeBasePerQuote(priceObject: any, assetMap: any) {
179
121
  }
180
122
 
181
123
  async function getHonestMoneyPerBts(referenceAsset: any, coreAsset: any) {
182
- const bridge = getHardcodedHonestMoneyBridge();
183
- const coreSide = [bridge.liquidityPool.reserves[0], bridge.liquidityPool.reserves[1]].find((asset) => asset.symbol === coreAsset.symbol);
184
- const referenceSide = [bridge.liquidityPool.reserves[0], bridge.liquidityPool.reserves[1]].find((asset) => asset.symbol === referenceAsset.symbol);
185
-
186
- if (!coreSide || !referenceSide) {
187
- return null;
188
- }
189
-
190
- const latestHonestMoneyPerBts = referenceSide.amount / coreSide.amount;
191
- if (!Number.isFinite(latestHonestMoneyPerBts) || latestHonestMoneyPerBts <= 0) {
124
+ // Prefer the live HONEST.MONEY/BTS pool (60s-cached); the module falls back
125
+ // to the hardcoded snapshot when the node cannot serve reserves. Reading the
126
+ // live bridge here keeps this report — whose purpose is refreshing those
127
+ // hardcoded values — from always printing stale fallback data.
128
+ const bridge = await getHonestMoneyBridge();
129
+ const latestHonestMoneyPerBts = bridge?.latestHonestMoneyPerBts ?? null;
130
+
131
+ if (latestHonestMoneyPerBts === null || !Number.isFinite(latestHonestMoneyPerBts) || latestHonestMoneyPerBts <= 0) {
192
132
  return null;
193
133
  }
194
134
 
@@ -197,8 +137,7 @@ async function getHonestMoneyPerBts(referenceAsset: any, coreAsset: any) {
197
137
  id: bridge.liquidityPool.id,
198
138
  poolSymbol: bridge.liquidityPool.poolSymbol,
199
139
  reserves: [
200
- bridge.liquidityPool.reserves[0],
201
- bridge.liquidityPool.reserves[1]
140
+ ...bridge.liquidityPool.reserves
202
141
  ],
203
142
  takerFeePercent: bridge.liquidityPool.takerFeePercent,
204
143
  withdrawalFeePercent: bridge.liquidityPool.withdrawalFeePercent
@@ -235,15 +174,12 @@ async function getReferenceFeedData(asset: any, referenceAsset: any, coreAsset:
235
174
  return null;
236
175
  }
237
176
 
238
- let assetPerBts = null;
239
177
  let btsPerAsset = null;
240
178
 
241
179
  if (settlementPrice.base.asset_id === asset.id && settlementPrice.quote.asset_id === coreAsset.id) {
242
- assetPerBts = basePerQuote;
243
180
  btsPerAsset = 1 / basePerQuote;
244
181
  } else if (settlementPrice.base.asset_id === coreAsset.id && settlementPrice.quote.asset_id === asset.id) {
245
182
  btsPerAsset = basePerQuote;
246
- assetPerBts = 1 / basePerQuote;
247
183
  } else {
248
184
  return null;
249
185
  }
@@ -345,7 +281,6 @@ async function main() {
345
281
  const scopedAssets = options.allMpas
346
282
  ? allAssets.filter(isMpa).sort((a, b) => a.symbol.localeCompare(b.symbol))
347
283
  : allAssets.filter((asset) => asset?.symbol?.startsWith(options.prefix)).sort((a, b) => a.symbol.localeCompare(b.symbol));
348
- const mpas = scopedAssets.filter(isMpa);
349
284
  const assetMap = new Map([coreAsset, referenceAsset, ...scopedAssets].filter(Boolean).map((asset) => [asset.id, asset]));
350
285
 
351
286
  const scopedAssetRecords = await mapWithConcurrency(scopedAssets, 4, async (asset: any) => {
@@ -4,13 +4,43 @@
4
4
  // the full claw catalog (via claw_manifest), so suppress incidental console
5
5
  // logs the same way claw_mcp_server does.
6
6
 
7
- import { describeMemuBridge } from '../modules/memu_bridge.js';
8
- import { success, failure, runMcpServer, createMessageParser } from '../modules/mcp_utils.js';
9
- import { runMemuCommand } from '../modules/memu_bridge.js';
7
+ import { createJsonRpcToolsHandler, jsonRpcError, runMcpServer } from '../modules/mcp_utils.js';
8
+ import { runMemuCommand, validateMemuCommandArgs } from '../modules/memu_bridge.js';
10
9
  import { pathToFileURL } from 'node:url';
10
+ import { getErrorMessage } from '../../modules/utils/errors.js';
11
11
 
12
12
  console.log = () => {};
13
13
  console.warn = () => {};
14
+
15
+ // MCP tool name -> runMemuCommand command.
16
+ const TOOL_COMMANDS: Record<string, string> = {
17
+ 'memu_manifest': 'manifest',
18
+ 'memu_memorize': 'memorize',
19
+ 'memu_retrieve': 'retrieve',
20
+ 'memu_list_categories': 'list-categories',
21
+ 'memu_list_items': 'list-items',
22
+ 'memu_create_item': 'create-item',
23
+ 'memu_update_item': 'update-item',
24
+ 'memu_delete_item': 'delete-item',
25
+ 'memu_clear': 'clear',
26
+ 'memu_status': 'status',
27
+ 'memu_memorize_conversation': 'memorize-conversation',
28
+ 'memu_memorize_trading_context': 'memorize-trading-context',
29
+ 'memu_retrieve_trading_context': 'retrieve-trading-context'
30
+ };
31
+
32
+ /**
33
+ * Redact a CLI argument that may carry secrets (LLM API keys, database DSNs).
34
+ * Malformed JSON must be reported without echoing the full raw value into
35
+ * error messages or process logs.
36
+ */
37
+ function redactSensitiveArg(value: any) {
38
+ const text = String(value);
39
+ const prefixLength = 12;
40
+ const prefix = text.slice(0, Math.min(prefixLength, text.length));
41
+ return `${prefix}<...${text.length} chars redacted>`;
42
+ }
43
+
14
44
  function parseArgs(argv: any) {
15
45
  const options: Record<string, any> = {};
16
46
 
@@ -33,8 +63,8 @@ function parseArgs(argv: any) {
33
63
  if (arg === '--llm-profile' && next) {
34
64
  try {
35
65
  options.llmProfiles = JSON.parse(next);
36
- } catch (e) {
37
- throw new Error(`Invalid JSON for --llm-profile: ${next}`);
66
+ } catch {
67
+ throw new Error(`Invalid JSON for --llm-profile: ${redactSensitiveArg(next)}`);
38
68
  }
39
69
  i += 1;
40
70
  continue;
@@ -43,8 +73,8 @@ function parseArgs(argv: any) {
43
73
  if (arg === '--db-config' && next) {
44
74
  try {
45
75
  options.databaseConfig = JSON.parse(next);
46
- } catch (e) {
47
- throw new Error(`Invalid JSON for --db-config: ${next}`);
76
+ } catch {
77
+ throw new Error(`Invalid JSON for --db-config: ${redactSensitiveArg(next)}`);
48
78
  }
49
79
  i += 1;
50
80
  continue;
@@ -54,7 +84,7 @@ function parseArgs(argv: any) {
54
84
  return options;
55
85
  }
56
86
 
57
- function listMcpTools() {
87
+ async function listMcpTools() {
58
88
  return [
59
89
  {
60
90
  name: 'memu_manifest',
@@ -286,158 +316,31 @@ function listMcpTools() {
286
316
  ];
287
317
  }
288
318
 
289
- async function handleRequest(message: any, defaults: any) {
290
- const { id, method, params } = message;
291
-
292
- switch (method) {
293
- case 'initialize':
294
- return success(id, {
295
- // Echo the client's requested protocol version when provided (JSONL
296
- // transport; see claw_runtime_matrix.ts).
297
- protocolVersion: params?.protocolVersion || '2024-11-05',
298
- capabilities: {
299
- tools: {
300
- listChanged: false
301
- }
302
- },
303
- serverInfo: {
304
- name: 'bitshares-memu',
305
- version: '0.1.0'
306
- }
307
- });
308
-
309
- case 'notifications/initialized':
310
- return;
311
-
312
- case 'ping':
313
- return success(id, {});
314
-
315
- case 'tools/list':
316
- return success(id, {
317
- tools: listMcpTools()
318
- });
319
-
320
- case 'tools/call': {
321
- const toolName = params?.name;
322
- const args = params?.arguments || {};
323
-
324
- try {
325
- let result;
326
-
327
- switch (toolName) {
328
- case 'memu_manifest':
329
- result = describeMemuBridge(defaults);
330
- break;
331
-
332
- case 'memu_memorize':
333
- if (!args.resourceUrl || !args.modality) {
334
- return failure(id, -32602, 'memu_memorize requires resourceUrl and modality');
335
- }
336
- result = await runMemuTool('memorize', args, defaults);
337
- break;
338
-
339
- case 'memu_retrieve':
340
- if (!args.queries) {
341
- return failure(id, -32602, 'memu_retrieve requires queries');
342
- }
343
- result = await runMemuTool('retrieve', args, defaults);
344
- break;
345
-
346
- case 'memu_list_categories':
347
- result = await runMemuTool('list-categories', args, defaults);
348
- break;
349
-
350
- case 'memu_list_items':
351
- result = await runMemuTool('list-items', args, defaults);
352
- break;
353
-
354
- case 'memu_create_item':
355
- if (!(args.categoryId || args.categoryName) || !args.summary) {
356
- return failure(id, -32602, 'memu_create_item requires categoryId or categoryName, plus summary');
357
- }
358
- result = await runMemuTool('create-item', args, defaults);
359
- break;
360
-
361
- case 'memu_update_item':
362
- if (!args.itemId || !args.updates) {
363
- return failure(id, -32602, 'memu_update_item requires itemId and updates');
364
- }
365
- result = await runMemuTool('update-item', args, defaults);
366
- break;
367
-
368
- case 'memu_delete_item':
369
- if (!args.itemId) {
370
- return failure(id, -32602, 'memu_delete_item requires itemId');
371
- }
372
- result = await runMemuTool('delete-item', args, defaults);
373
- break;
374
-
375
- case 'memu_clear':
376
- result = await runMemuTool('clear', args, defaults);
377
- break;
378
-
379
- case 'memu_status':
380
- result = await runMemuTool('status', args, defaults);
381
- break;
382
-
383
- case 'memu_memorize_conversation':
384
- if (!args.messages) {
385
- return failure(id, -32602, 'memu_memorize_conversation requires messages');
386
- }
387
- result = await runMemuTool('memorize-conversation', args, defaults);
388
- break;
389
-
390
- case 'memu_memorize_trading_context':
391
- if (!args.context) {
392
- return failure(id, -32602, 'memu_memorize_trading_context requires context');
393
- }
394
- result = await runMemuTool('memorize-trading-context', args, defaults);
395
- break;
396
-
397
- case 'memu_retrieve_trading_context':
398
- if (!args.query) {
399
- return failure(id, -32602, 'memu_retrieve_trading_context requires query');
400
- }
401
- result = await runMemuTool('retrieve-trading-context', args, defaults);
402
- break;
403
-
404
- default:
405
- return failure(id, -32602, `Unknown tool: ${toolName}`);
406
- }
407
-
408
- return success(id, {
409
- content: [
410
- {
411
- type: 'text',
412
- text: JSON.stringify(result, null, 2)
413
- }
414
- ],
415
- structuredContent: result
416
- });
417
- } catch (error: any) {
418
- return success(id, {
419
- content: [
420
- {
421
- type: 'text',
422
- text: error && error.stack ? error.stack : String(error)
423
- }
424
- ],
425
- isError: true
426
- });
427
- }
428
- }
319
+ async function callTool(params: any, defaults: any) {
320
+ const toolName = params?.name;
321
+ const command = TOOL_COMMANDS[toolName];
322
+ if (!command) {
323
+ throw jsonRpcError(-32602, `Unknown tool: ${toolName}`);
324
+ }
429
325
 
430
- default:
431
- if (id !== undefined) {
432
- return failure(id, -32601, `Method not found: ${method}`);
433
- }
326
+ const args = params?.arguments || {};
327
+ // Shared validation with runMemuCommand/claw_bridge so every surface rejects
328
+ // missing args with the same message; surfaced as invalid params (-32602).
329
+ try {
330
+ validateMemuCommandArgs(command, { ...defaults, ...args });
331
+ } catch (err: any) {
332
+ throw jsonRpcError(-32602, getErrorMessage(err));
434
333
  }
435
- }
436
334
 
437
- async function runMemuTool(command: any, args: any, defaults: any) {
438
335
  return runMemuCommand(command, { ...defaults, ...args });
439
336
  }
440
337
 
338
+ const handleRequest = createJsonRpcToolsHandler({
339
+ serverName: 'bitshares-memu',
340
+ listTools: listMcpTools,
341
+ callTool
342
+ });
343
+
441
344
  if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
442
345
  runMcpServer(parseArgs, handleRequest).catch((err: unknown) => {
443
346
  process.stderr.write(`${err instanceof Error && err.stack ? err.stack : String(err)}\n`);
@@ -445,5 +348,4 @@ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href)
445
348
  });
446
349
  }
447
350
 
448
- export { createMessageParser, failure, handleRequest, listMcpTools, success }
449
351
 
@@ -225,6 +225,9 @@ function createBridgeHarness() {
225
225
  }
226
226
  });
227
227
 
228
+ // Snapshot the real validator before the mock replaces the module: claw
229
+ // bridge delegates memu-* argument validation to it.
230
+ const realMemuBridge = require(memuBridgePath);
228
231
  registerMock(memuBridgePath, {
229
232
  describeMemuBridge: (options: any) => ({
230
233
  options,
@@ -238,7 +241,8 @@ function createBridgeHarness() {
238
241
  options,
239
242
  source: 'memu'
240
243
  };
241
- }
244
+ },
245
+ validateMemuCommandArgs: realMemuBridge.validateMemuCommandArgs
242
246
  });
243
247
 
244
248
  clearModule(bridgePath);
@@ -499,7 +503,7 @@ async function testRunClawCommandDispatchMatrix() {
499
503
  () => bridge.runClawCommand('memu-create-item', {
500
504
  summary: 'missing category'
501
505
  }),
502
- /memu-create-item requires categoryId or categoryName, plus summary/
506
+ /create-item requires categoryId or categoryName, plus summary/
503
507
  );
504
508
 
505
509
  await assert.rejects(
@@ -31,7 +31,7 @@ async function testParserAcceptsJsonlAcrossChunksAndSingleBuffer() {
31
31
  capabilities: {},
32
32
  clientInfo: {
33
33
  name: 'claw-mcp-transport-test',
34
- version: '1.4.20'
34
+ version: '1.4.21'
35
35
  },
36
36
  protocolVersion: '2024-11-05'
37
37
  }
@@ -182,7 +182,7 @@ async function testMainEntrypointHandlesRealProcessInitialize() {
182
182
  capabilities: {},
183
183
  clientInfo: {
184
184
  name: 'claw-mcp-transport-test',
185
- version: '1.4.20'
185
+ version: '1.4.21'
186
186
  },
187
187
  protocolVersion: '2024-11-05'
188
188
  }
@@ -85,7 +85,7 @@ function main() {
85
85
  if (e.code === 'ENOENT') {
86
86
  console.error(`Data file not found: ${opts.data}`);
87
87
  console.error('Export LP candles first, or point --data at an existing file.');
88
- console.error(' tsx market_adapter/inputs/fetch_lp_data.ts --pool 133 --precA 4 --precB 5 --interval 1h --lookback 26280h');
88
+ console.error(' node dist/market_adapter/inputs/fetch_lp_data.js --pool 133 --precA 4 --precB 5 --interval 1h --lookback 26280h');
89
89
  }
90
90
  else if (e instanceof SyntaxError) {
91
91
  console.error(`Failed to parse JSON from: ${opts.data}`);