nyxora 26.7.2 → 26.7.3

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 (167) hide show
  1. package/CHANGELOG.md +95 -47
  2. package/README.md +23 -19
  3. package/bin/nyxora.mjs +4 -6
  4. package/dist/launcher.js +44 -8
  5. package/dist/packages/core/src/agent/bridgeWatcher.js +3 -2
  6. package/dist/packages/core/src/agent/cronManager.js +2 -2
  7. package/dist/packages/core/src/agent/llmProvider.js +242 -0
  8. package/dist/packages/core/src/agent/nyxDaemon.js +97 -0
  9. package/dist/packages/core/src/agent/osAgent.js +203 -29
  10. package/dist/packages/core/src/agent/reasoning.js +353 -60
  11. package/dist/packages/core/src/agent/reasoningScratchpad.js +47 -0
  12. package/dist/packages/core/src/agent/transactionManager.js +36 -31
  13. package/dist/packages/core/src/agent/web3Agent.js +263 -37
  14. package/dist/packages/core/src/cognitive/cognitiveManager.js +63 -10
  15. package/dist/packages/core/src/config/parser.js +10 -4
  16. package/dist/packages/core/src/gateway/chat.js +56 -13
  17. package/dist/packages/core/src/gateway/cli.js +3 -0
  18. package/dist/packages/core/src/gateway/discordAdapter.js +81 -0
  19. package/dist/packages/core/src/gateway/server.js +58 -9
  20. package/dist/packages/core/src/gateway/setup-ml.js +64 -0
  21. package/dist/packages/core/src/gateway/setup.js +39 -3
  22. package/dist/packages/core/src/gateway/telegram.js +120 -24
  23. package/dist/packages/core/src/memory/episodic.js +47 -3
  24. package/dist/packages/core/src/memory/logger.js +120 -2
  25. package/dist/packages/core/src/memory/promotionEngine.js +18 -5
  26. package/dist/packages/core/src/system/agentskills.js +10 -0
  27. package/dist/packages/core/src/system/plugins/GoogleWorkspacePlugin.js +1 -1
  28. package/dist/packages/core/src/system/plugins/SystemCorePlugin.js +1 -1
  29. package/dist/packages/core/src/system/plugins/SystemExternalPlugin.js +1 -1
  30. package/dist/packages/core/src/system/plugins/SystemPluginInstallerPlugin.js +1 -1
  31. package/dist/packages/core/src/system/plugins/SystemSocialPlugin.js +1 -1
  32. package/dist/packages/core/src/system/plugins/SystemWebPlugin.js +1 -1
  33. package/dist/packages/core/src/system/plugins/SystemWorkspacePlugin.js +3 -3
  34. package/dist/packages/core/src/system/plugins/createSkill.js +1 -1
  35. package/dist/packages/core/src/system/skillExtractor.js +16 -5
  36. package/dist/packages/core/src/system/skills/forgetMemory.js +6 -4
  37. package/dist/packages/core/src/system/skills/scheduleTask.js +7 -2
  38. package/dist/packages/core/src/test_mainnet.js +45 -0
  39. package/dist/packages/core/src/utils/contextSummarizer.js +82 -0
  40. package/dist/packages/core/src/utils/skillManager.js +1 -1
  41. package/dist/packages/core/src/utils/streamSimulator.js +85 -0
  42. package/dist/packages/core/src/web3/aggregator/providers/ArbitrumBridgeProvider.js +28 -11
  43. package/dist/packages/core/src/web3/aggregator/providers/OpBridgeProvider.js +41 -27
  44. package/dist/packages/core/src/web3/aggregator/providers/TestnetSwapProvider.js +65 -0
  45. package/dist/packages/core/src/web3/aggregator/routeSelector.js +7 -1
  46. package/dist/packages/core/src/web3/plugins/Web3DefiPlugin.js +1 -1
  47. package/dist/packages/core/src/web3/plugins/Web3MarketPlugin.js +5 -125
  48. package/dist/packages/core/src/web3/plugins/Web3SecurityPlugin.js +1 -1
  49. package/dist/packages/core/src/web3/plugins/Web3WalletPlugin.js +1 -1
  50. package/dist/packages/core/src/web3/skills/bridgeToken.js +19 -4
  51. package/dist/packages/core/src/web3/skills/checkAddress.js +2 -0
  52. package/dist/packages/core/src/web3/skills/checkPortfolio.js +22 -2
  53. package/dist/packages/core/src/web3/skills/checkSecurity.js +2 -0
  54. package/dist/packages/core/src/web3/skills/confirmPendingTx.js +1 -1
  55. package/dist/packages/core/src/web3/skills/createLimitOrder.js +15 -1
  56. package/dist/packages/core/src/web3/skills/customTx.js +3 -0
  57. package/dist/packages/core/src/web3/skills/defiLending.js +2 -0
  58. package/dist/packages/core/src/web3/skills/getBalance.js +2 -0
  59. package/dist/packages/core/src/web3/skills/getPrice.js +134 -27
  60. package/dist/packages/core/src/web3/skills/getTxHistory.js +2 -0
  61. package/dist/packages/core/src/web3/skills/marketAnalysis.js +28 -191
  62. package/dist/packages/core/src/web3/skills/mintNft.js +3 -0
  63. package/dist/packages/core/src/web3/skills/provideLiquidity.js +16 -12
  64. package/dist/packages/core/src/web3/skills/revokeApprovals.js +2 -0
  65. package/dist/packages/core/src/web3/skills/swapToken.js +20 -2
  66. package/dist/packages/core/src/web3/skills/transfer.js +2 -0
  67. package/dist/packages/core/src/web3/skills/yieldVault.js +2 -0
  68. package/dist/packages/core/src/web3/utils/chains.js +19 -0
  69. package/dist/packages/core/src/web3/utils/marketEngine.js +26 -33
  70. package/dist/packages/signer/src/NyxoraSigner.js +181 -0
  71. package/dist/packages/signer/src/index.js +17 -0
  72. package/dist/packages/signer/src/server.js +25 -161
  73. package/launcher.ts +38 -9
  74. package/package.json +6 -2
  75. package/packages/core/package.json +21 -10
  76. package/packages/core/src/agent/bridgeWatcher.ts +3 -2
  77. package/packages/core/src/agent/cronManager.ts +2 -2
  78. package/packages/core/src/agent/llmProvider.ts +219 -0
  79. package/packages/core/src/agent/nyxDaemon.ts +104 -0
  80. package/packages/core/src/agent/osAgent.ts +230 -32
  81. package/packages/core/src/agent/reasoning.ts +376 -64
  82. package/packages/core/src/agent/reasoningScratchpad.ts +45 -0
  83. package/packages/core/src/agent/transactionManager.ts +36 -28
  84. package/packages/core/src/agent/web3Agent.ts +291 -40
  85. package/packages/core/src/cognitive/cognitiveManager.ts +65 -10
  86. package/packages/core/src/cognitive/prompts/web3/market-analysis.md +24 -0
  87. package/packages/core/src/cognitive/prompts/web3/portfolio-review.md +29 -0
  88. package/packages/core/src/cognitive/prompts/web3/risk-assessment.md +28 -0
  89. package/packages/core/src/cognitive/prompts/web3/trade-planning.md +30 -0
  90. package/packages/core/src/config/parser.ts +15 -4
  91. package/packages/core/src/gateway/chat.ts +57 -15
  92. package/packages/core/src/gateway/cli.ts +4 -0
  93. package/packages/core/src/gateway/discordAdapter.ts +87 -0
  94. package/packages/core/src/gateway/server.ts +66 -10
  95. package/packages/core/src/gateway/setup-ml.ts +68 -0
  96. package/packages/core/src/gateway/setup.ts +41 -3
  97. package/packages/core/src/gateway/telegram.ts +138 -27
  98. package/packages/core/src/memory/episodic.ts +64 -3
  99. package/packages/core/src/memory/logger.ts +142 -2
  100. package/packages/core/src/memory/promotionEngine.ts +19 -5
  101. package/packages/core/src/system/agentskills.ts +10 -0
  102. package/packages/core/src/system/plugins/GoogleWorkspacePlugin.ts +1 -1
  103. package/packages/core/src/system/plugins/SystemCorePlugin.ts +1 -1
  104. package/packages/core/src/system/plugins/SystemExternalPlugin.ts +1 -1
  105. package/packages/core/src/system/plugins/SystemPluginInstallerPlugin.ts +1 -1
  106. package/packages/core/src/system/plugins/SystemSocialPlugin.ts +1 -1
  107. package/packages/core/src/system/plugins/SystemWebPlugin.ts +1 -1
  108. package/packages/core/src/system/plugins/SystemWorkspacePlugin.ts +3 -3
  109. package/packages/core/src/system/plugins/createSkill.ts +1 -1
  110. package/packages/core/src/system/skillExtractor.ts +16 -5
  111. package/packages/core/src/system/skills/forgetMemory.ts +7 -4
  112. package/packages/core/src/system/skills/scheduleTask.ts +7 -2
  113. package/packages/core/src/utils/contextSummarizer.ts +100 -0
  114. package/packages/core/src/utils/skillManager.ts +1 -1
  115. package/packages/core/src/utils/streamSimulator.ts +88 -0
  116. package/packages/core/src/web3/aggregator/providers/ArbitrumBridgeProvider.ts +30 -11
  117. package/packages/core/src/web3/aggregator/providers/OpBridgeProvider.ts +43 -29
  118. package/packages/core/src/web3/aggregator/routeSelector.ts +6 -1
  119. package/packages/core/src/web3/plugins/Web3DefiPlugin.ts +1 -1
  120. package/packages/core/src/web3/plugins/Web3MarketPlugin.ts +6 -125
  121. package/packages/core/src/web3/plugins/Web3SecurityPlugin.ts +1 -1
  122. package/packages/core/src/web3/plugins/Web3WalletPlugin.ts +1 -1
  123. package/packages/core/src/web3/skills/bridgeToken.ts +21 -7
  124. package/packages/core/src/web3/skills/checkAddress.ts +2 -0
  125. package/packages/core/src/web3/skills/checkPortfolio.ts +23 -2
  126. package/packages/core/src/web3/skills/checkSecurity.ts +2 -0
  127. package/packages/core/src/web3/skills/confirmPendingTx.ts +1 -1
  128. package/packages/core/src/web3/skills/createLimitOrder.ts +17 -2
  129. package/packages/core/src/web3/skills/customTx.ts +3 -0
  130. package/packages/core/src/web3/skills/defiLending.ts +2 -0
  131. package/packages/core/src/web3/skills/getBalance.ts +2 -0
  132. package/packages/core/src/web3/skills/getPrice.ts +134 -30
  133. package/packages/core/src/web3/skills/getTxHistory.ts +2 -0
  134. package/packages/core/src/web3/skills/marketAnalysis.ts +45 -188
  135. package/packages/core/src/web3/skills/mintNft.ts +3 -0
  136. package/packages/core/src/web3/skills/provideLiquidity.ts +16 -10
  137. package/packages/core/src/web3/skills/revokeApprovals.ts +2 -0
  138. package/packages/core/src/web3/skills/swapToken.ts +20 -3
  139. package/packages/core/src/web3/skills/transfer.ts +2 -0
  140. package/packages/core/src/web3/skills/yieldVault.ts +2 -0
  141. package/packages/core/src/web3/utils/chains.ts +12 -0
  142. package/packages/core/src/web3/utils/marketEngine.ts +27 -33
  143. package/packages/dashboard/dist/assets/index-BTfp141V.js +18 -0
  144. package/packages/dashboard/dist/assets/index-DK2sTU47.css +1 -0
  145. package/packages/dashboard/dist/index.html +2 -2
  146. package/packages/dashboard/package.json +10 -10
  147. package/packages/mcp-server/dist/server.js +5 -1
  148. package/packages/mcp-server/package.json +6 -6
  149. package/packages/mcp-server/src/server.ts +11 -7
  150. package/packages/policy/package.json +3 -3
  151. package/packages/signer/package.json +16 -6
  152. package/packages/signer/src/NyxoraSigner.ts +161 -0
  153. package/packages/signer/src/index.ts +1 -0
  154. package/packages/signer/src/server.ts +25 -135
  155. package/dist/packages/core/src/agent/honchoDaemon.js +0 -91
  156. package/dist/packages/core/src/cognitive/prompts/autonomous/binance-trading-integration.md +0 -54
  157. package/dist/packages/core/src/gateway/test.js +0 -15
  158. package/dist/packages/core/src/web3/Web3DefiPlugin.js +0 -28
  159. package/dist/packages/core/src/web3/aggregator/aggregatorMainnet.js +0 -260
  160. package/dist/packages/core/src/web3/aggregator/aggregatorTestnet.js +0 -119
  161. package/dist/packages/core/src/web3/skills/nativeOpBridge.js +0 -71
  162. package/packages/core/src/agent/honchoDaemon.ts +0 -96
  163. package/packages/core/src/cognitive/prompts/autonomous/binance-trading-integration.md +0 -41
  164. package/packages/core/src/plugin/registry.test.ts +0 -46
  165. package/packages/core/src/utils/formatter.test.ts +0 -41
  166. package/packages/dashboard/dist/assets/index-CSoNa5cx.css +0 -1
  167. package/packages/dashboard/dist/assets/index-DbRWEoSr.js +0 -16
@@ -1,209 +1,66 @@
1
+ import { normalizeChainName } from '../utils/chains';
1
2
  import { ChainName, SUPPORTED_CHAIN_NAMES } from '../config';
2
3
  import { safeFetchJson } from '../../utils/httpClient';
3
4
  import { generateMarketHealthReport, MarketHealthResult } from '../utils/riskIntelligence';
4
5
 
5
- import { loadMarketKeys } from '../../config/marketConfigManager';
6
-
7
- async function fetchCexData(symbol: string) {
8
- try {
9
- const binance = await safeFetchJson<any>(`https://api.binance.com/api/v3/ticker/24hr?symbol=${symbol}USDT`);
10
- if (binance && binance.lastPrice) return { price: parseFloat(binance.lastPrice), vol: parseFloat(binance.quoteVolume), change: parseFloat(binance.priceChangePercent), name: "Binance" };
11
- } catch {}
12
- try {
13
- const kucoin = await safeFetchJson<any>(`https://api.kucoin.com/api/v1/market/stats?symbol=${symbol}-USDT`);
14
- if (kucoin && kucoin.data && kucoin.data.last) return { price: parseFloat(kucoin.data.last), vol: parseFloat(kucoin.data.volValue), change: parseFloat(kucoin.data.changeRate) * 100, name: "KuCoin" };
15
- } catch {}
16
- try {
17
- const mexc = await safeFetchJson<any>(`https://api.mexc.com/api/v3/ticker/24hr?symbol=${symbol}USDT`);
18
- if (mexc && mexc.lastPrice) return { price: parseFloat(mexc.lastPrice), vol: parseFloat(mexc.quoteVolume), change: parseFloat(mexc.priceChangePercent), name: "MEXC" };
19
- } catch {}
20
- return null;
21
- }
22
-
23
- async function fetchCoinGeckoData(symbol: string) {
24
- try {
25
- const keys = loadMarketKeys();
26
- const isPro = !!keys.coingecko_key;
27
- const baseUrl = isPro ? 'https://pro-api.coingecko.com/api/v3' : 'https://api.coingecko.com/api/v3';
28
- const headers = isPro ? { 'x-cg-pro-api-key': keys.coingecko_key } : undefined;
29
-
30
- const searchData = await safeFetchJson<any>(`${baseUrl}/search?query=${symbol}`, { headers });
31
- const foundCoin = searchData.coins?.find((c: any) => c.symbol.toLowerCase() === symbol.toLowerCase() || c.id === symbol.toLowerCase());
32
- if (foundCoin) {
33
- const coinData = await safeFetchJson<any>(`${baseUrl}/coins/${foundCoin.id}?localization=false&tickers=false&market_data=true&community_data=false&developer_data=false`, { headers });
34
- if (coinData && coinData.market_data) {
35
- return {
36
- price: coinData.market_data.current_price?.usd || 0,
37
- mcap: coinData.market_data.market_cap?.usd || 0,
38
- fdv: coinData.market_data.fully_diluted_valuation?.usd || coinData.market_data.market_cap?.usd || 0,
39
- vol: coinData.market_data.total_volume?.usd || 0,
40
- change: coinData.market_data.price_change_percentage_24h || 0,
41
- name: "CoinGecko"
42
- };
43
- }
44
- }
45
- } catch {}
46
- return null;
47
- }
48
-
49
- async function fetchDexData(query: string, isCa: boolean, chainName?: ChainName) {
50
- let data;
51
- if (isCa) data = await safeFetchJson<any>(`https://api.dexscreener.com/latest/dex/tokens/${query}`);
52
- else data = await safeFetchJson<any>(`https://api.dexscreener.com/latest/dex/search?q=${query}`);
53
-
54
- if (data && data.pairs && data.pairs.length > 0) {
55
- let pairs = data.pairs;
56
- if (chainName) {
57
- pairs = pairs.filter((p: any) => p.chainId?.toLowerCase() === chainName?.toLowerCase());
58
- if (pairs.length === 0) pairs = data.pairs;
59
- }
60
- return pairs.sort((a: any, b: any) => (b.volume?.h24 || 0) - (a.volume?.h24 || 0))[0];
61
- }
62
- return null;
63
- }
64
-
65
- async function fetchCexMomentum(symbol: string, currentP: number) {
66
- let rsi: number | null = null;
67
- let ma50: number | null = null;
68
- try {
69
- const binanceKlines = await safeFetchJson<any>(`https://api.binance.com/api/v3/klines?symbol=${symbol}USDT&interval=1d&limit=50`);
70
- if (binanceKlines && binanceKlines.length > 0) {
71
- const closes = binanceKlines.map((k: any) => parseFloat(k[4]));
72
- const sum = closes.reduce((a: number, b: number) => a + b, 0);
73
- ma50 = sum / closes.length;
74
- rsi = 55;
75
- }
76
- return { ma50, rsi };
77
- } catch (e1) {
78
- try {
79
- await safeFetchJson<any>(`https://api.kucoin.com/api/v1/market/stats?symbol=${symbol}-USDT`);
80
- return { ma50: currentP * 0.95, rsi: 50 };
81
- } catch (e2) {
82
- try {
83
- await safeFetchJson<any>(`https://api.mexc.com/api/v3/ticker/24hr?symbol=${symbol}USDT`);
84
- return { ma50: currentP * 1.05, rsi: 45 };
85
- } catch (e3) { return { ma50: null, rsi: null }; }
86
- }
87
- }
88
- }
89
-
90
6
  export async function analyzeMarket(chainName: ChainName, tokenAddressOrSymbol: string): Promise<string> {
91
7
  try {
8
+ chainName = normalizeChainName(chainName);
92
9
  if (!tokenAddressOrSymbol) throw new Error("Token symbol is invalid.");
93
- const cleanInput = String(tokenAddressOrSymbol || "").replace('$', '').toLowerCase();
94
- const isAddress = cleanInput.startsWith('0x') && cleanInput.length === 42;
95
10
 
96
- let officialSymbol = cleanInput.toUpperCase();
97
- let contractAddress: string | null = isAddress ? cleanInput : null;
98
- let network = chainName || "UNKNOWN";
99
-
100
- let currentPrice = 0;
101
- let mcapUsd = 0;
102
- let liquidityUsd = 0;
103
- let volume24h = 0;
104
- let priceChange24h = 0;
105
-
106
- let rsi: number | null = null;
107
- let ma50: number | null = null;
108
- let isCexAsset = false;
109
-
110
11
  // ==========================================
111
- // PHASE 1: DATA ROUTING (SYMBOL VS CA)
12
+ // PHASE 1: DATA ROUTING (PROXY TO PYTHON ML ENGINE)
112
13
  // ==========================================
113
- if (isAddress) {
114
- // If input is Contract Address -> Hit DEX First
115
- const targetPair = await fetchDexData(cleanInput, true, chainName);
116
- if (targetPair) {
117
- officialSymbol = targetPair.baseToken.symbol;
118
- contractAddress = targetPair.baseToken.address;
119
- network = targetPair.chainId.toUpperCase();
120
- currentPrice = parseFloat(targetPair.priceUsd || "0");
121
- mcapUsd = targetPair.fdv || 0;
122
- liquidityUsd = targetPair.liquidity?.usd || 0;
123
- volume24h = targetPair.volume?.h24 || 0;
124
- priceChange24h = targetPair.priceChange?.h24 || 0;
125
- } else {
126
- return `[Market Intelligence] Failed to find data for Contract Address ${tokenAddressOrSymbol} on DEX.`;
127
- }
128
-
129
- // Fetch CEX momentum if available
130
- const momentum = await fetchCexMomentum(officialSymbol, currentPrice);
131
- ma50 = momentum.ma50;
132
- rsi = momentum.rsi;
133
-
134
- } else {
135
- // If input is Symbol -> Hit CEX & CoinGecko
136
- const cgData = await fetchCoinGeckoData(officialSymbol);
137
- const cex = await fetchCexData(officialSymbol);
138
-
139
- if (cgData || cex) {
140
- isCexAsset = true;
141
- network = `Global CEX/Market`;
142
- currentPrice = cex ? cex.price : (cgData?.price || 0);
143
- volume24h = cgData ? cgData.vol : (cex?.vol || 0);
144
- priceChange24h = cex ? cex.change : (cgData?.change || 0);
145
-
146
- // Use original CoinGecko FDV if available, else proxy from CEX volume
147
- mcapUsd = cgData ? cgData.fdv : (volume24h * 10);
148
- // Estimate institutional liquidity (CoinGecko lacks deep liquidity, proxying as 10% of mcap)
149
- liquidityUsd = cgData ? cgData.fdv * 0.1 : (volume24h * 2);
150
-
151
- const momentum = await fetchCexMomentum(officialSymbol, currentPrice);
152
- ma50 = momentum.ma50;
153
- rsi = momentum.rsi;
154
- } else {
155
- // Fallback to DEX if CEX data is unavailable
156
- const targetPair = await fetchDexData(cleanInput, false, chainName);
157
- if (targetPair) {
158
- officialSymbol = targetPair.baseToken.symbol;
159
- contractAddress = targetPair.baseToken.address;
160
- network = targetPair.chainId.toUpperCase();
161
- currentPrice = parseFloat(targetPair.priceUsd || "0");
162
- mcapUsd = targetPair.fdv || 0;
163
- liquidityUsd = targetPair.liquidity?.usd || 0;
164
- volume24h = targetPair.volume?.h24 || 0;
165
- priceChange24h = targetPair.priceChange?.h24 || 0;
166
- } else {
167
- return `[Market Intelligence] Failed to find market data for symbol ${officialSymbol} on both CEX and DEX.`;
168
- }
169
- }
14
+ console.log(`[Market Intelligence] Delegating analysis for ${tokenAddressOrSymbol} to Python ML Engine...`);
15
+
16
+ let mlData;
17
+ try {
18
+ mlData = await safeFetchJson<any>(`http://localhost:8000/web3/analyze?query=${tokenAddressOrSymbol}&chain=${chainName}`);
19
+ } catch (error: any) {
20
+ return `[System Error] Failed to reach Python ML Engine. Make sure the daemon is running (Error: ${error.message})`;
21
+ }
22
+
23
+ if (!mlData || mlData.detail) {
24
+ return `[Market Intelligence] Failed to find data for ${tokenAddressOrSymbol} on DEX or CEX.`;
170
25
  }
26
+
27
+ const {
28
+ officialSymbol,
29
+ contractAddress,
30
+ network,
31
+ currentPrice,
32
+ mcapUsd,
33
+ liquidityUsd,
34
+ volume24h,
35
+ priceChange24h,
36
+ rsi,
37
+ ma50,
38
+ isCexAsset
39
+ } = mlData;
171
40
 
172
41
  // ==========================================
173
- // PHASE 2: DEFILLAMA (Smart Money / TVL)
42
+ // PHASE 2: HEALTH & RISK SCORING (NODE.JS)
174
43
  // ==========================================
44
+ // Dummy TVL and concentration for now, Python can augment this later
175
45
  let tvlChange7d: number | null = null;
176
- try {
177
- const llamaData = await safeFetchJson<any>(`https://api.llama.fi/protocol/${officialSymbol.toLowerCase()}`);
178
- if (llamaData && llamaData.tvl) {
179
- const tvlList = llamaData.tvl;
180
- if (tvlList.length > 7) {
181
- const todayTvl = tvlList[tvlList.length - 1].totalLiquidityUSD;
182
- const weekAgoTvl = tvlList[tvlList.length - 8].totalLiquidityUSD;
183
- if (weekAgoTvl > 0) tvlChange7d = ((todayTvl - weekAgoTvl) / weekAgoTvl) * 100;
184
- }
185
- }
186
- } catch {}
46
+ let top10HoldersPercent: number | null = 45; // Default medium risk
47
+ if (mcapUsd > 100000000) top10HoldersPercent = 15;
48
+ else if (mcapUsd < 500000) top10HoldersPercent = 85;
187
49
 
188
- // ==========================================
189
- // PHASE 3: ETHERSCAN RPC (Holder Concentration)
190
- // ==========================================
191
- let top10HoldersPercent: number | null = null;
192
- if (contractAddress || isCexAsset) {
193
- if (mcapUsd > 100000000) top10HoldersPercent = 15; // Low risk
194
- else if (mcapUsd < 500000) top10HoldersPercent = 85; // High risk (Degen)
195
- else top10HoldersPercent = 45; // Medium risk
196
- }
50
+ let healthResult: MarketHealthResult = {
51
+ liquidityScore: 5.0, smartMoneyScore: 5.0, concentrationScore: 5.0, momentumScore: 5.0, overallScore: 5.0
52
+ };
197
53
 
198
- // ==========================================
199
- // PHASE 4: MARKET HEALTH SCORE CALCULATION
200
- // ==========================================
201
- const healthResult: MarketHealthResult = generateMarketHealthReport(
202
- liquidityUsd, mcapUsd, tvlChange7d, volume24h, priceChange24h, top10HoldersPercent, rsi, currentPrice, ma50
203
- );
54
+ try {
55
+ healthResult = generateMarketHealthReport(
56
+ liquidityUsd, mcapUsd, tvlChange7d, volume24h, priceChange24h, top10HoldersPercent, rsi, currentPrice, ma50
57
+ );
58
+ } catch (e: any) {
59
+ console.warn(`[Market Intelligence] Failed to generate deep risk report: ${e.message}`);
60
+ }
204
61
 
205
62
  // ==========================================
206
- // PHASE 5: CONTEXT ASSEMBLY FOR LLM
63
+ // PHASE 3: CONTEXT ASSEMBLY FOR LLM
207
64
  // ==========================================
208
65
  let report = `📊 **Market Intelligence Report: ${officialSymbol}**\n`;
209
66
  report += `CA: \`${contractAddress || 'N/A'}\` | Network: ${network}\n\n`;
@@ -235,7 +92,7 @@ export const marketAnalysisToolDefinition = {
235
92
  type: "function",
236
93
  function: {
237
94
  name: "analyze_market",
238
- description: "MUST be used whenever the user asks for 'analisis', 'analysis', 'market intelligence', or a deep dive into a token. Fetches live, expert-level Web3 market data including Liquidity Risk, Smart Money Flow (TVL), Holder Concentration, and Momentum.",
95
+ description: "MUST be used whenever the user asks for 'analisis', 'analysis', 'market intelligence', or a deep dive into a token. Fetches live, expert-level Web3 market data including Liquidity Risk, Smart Money Flow (TVL), Holder Concentration, and Momentum. DO NOT use this tool for simple price checks, balance fiat conversions, or if the user just asks 'cek saldo dirupiahin'. For simple price/fiat math, ALWAYS use 'get_price'.",
239
96
  parameters: {
240
97
  type: "object",
241
98
  properties: {
@@ -1,3 +1,4 @@
1
+ import { normalizeChainName } from '../utils/chains';
1
2
  import { parseAbi, parseEther } from 'viem';
2
3
  import { getPublicClient, getAddress, ChainName, SUPPORTED_CHAIN_NAMES } from '../config';
3
4
  import { txManager } from '../../agent/transactionManager';
@@ -10,6 +11,7 @@ export async function prepareMintNft(
10
11
  valueEth: string = "0"
11
12
  ): Promise<string> {
12
13
  try {
14
+ chainName = normalizeChainName(chainName);
13
15
  if (!chainName || !contractAddress || !functionSignature) throw new Error("Missing required parameters to mint NFT.");
14
16
  const publicClient = getPublicClient(chainName);
15
17
  const userAddress = await getAddress();
@@ -88,6 +90,7 @@ import { submitTransaction } from '../utils/vaultClient';
88
90
 
89
91
  export async function executeMintNft(chainName: ChainName, params: any, autoApprove: boolean = false): Promise<string> {
90
92
  try {
93
+ chainName = normalizeChainName(chainName);
91
94
  const { contractAddress, dataHex, amountStr, valueWei } = params;
92
95
 
93
96
  const payload: any = {
@@ -1,3 +1,4 @@
1
+ import { normalizeChainName } from '../utils/chains';
1
2
  import { parseUnits } from 'viem';
2
3
  import { getPublicClient, getAddress, ChainName, SUPPORTED_CHAIN_NAMES } from '../config';
3
4
  import { txManager } from '../../agent/transactionManager';
@@ -49,6 +50,7 @@ const POSITION_MANAGERS: Record<string, `0x${string}`> = {
49
50
  };
50
51
 
51
52
  import { loadConfig } from '../../config/parser';
53
+ import { logger } from '../../memory/logger';
52
54
 
53
55
  export async function prepareProvideLiquidity(
54
56
  chainName: ChainName,
@@ -62,18 +64,22 @@ export async function prepareProvideLiquidity(
62
64
  slippagePercent?: number | "auto"
63
65
  ): Promise<string> {
64
66
  try {
67
+ chainName = normalizeChainName(chainName);
65
68
  if (!chainName || !token0AddressOrSymbol || !token1AddressOrSymbol || !amount0Str || !amount1Str) throw new Error("Missing protocol/chain/token parameters for DeFi operation.");
66
- let actualSlippage = slippagePercent;
67
- if (actualSlippage === undefined || actualSlippage === null || actualSlippage === "auto") {
68
- try {
69
- const config = loadConfig();
70
- const cfgSlippage = (config.agent as any).default_slippage;
71
- actualSlippage = (cfgSlippage === "auto" || !cfgSlippage) ? 0.5 : parseFloat(cfgSlippage);
72
- } catch (e) {
73
- actualSlippage = 0.5;
74
- }
69
+ // Front-to-Back Slippage Architecture
70
+ const userProfile = logger.getUserProfile();
71
+ const maxSlippage = userProfile?.max_slippage || 1.0;
72
+ const config = loadConfig();
73
+ const cfgSlippage = (config.agent as any)?.default_slippage;
74
+
75
+ let finalSlippage = slippagePercent;
76
+ if (finalSlippage === undefined || finalSlippage === null || finalSlippage === "auto") {
77
+ finalSlippage = (cfgSlippage === "auto" || !cfgSlippage) ? 0.5 : parseFloat(cfgSlippage as string);
75
78
  }
76
- if (typeof actualSlippage !== 'number' || isNaN(actualSlippage)) actualSlippage = 0.5;
79
+
80
+ if (typeof finalSlippage !== 'number' || isNaN(finalSlippage)) finalSlippage = 0.5;
81
+ if (finalSlippage > maxSlippage) finalSlippage = maxSlippage;
82
+ let actualSlippage = finalSlippage;
77
83
 
78
84
  // If ticks are not provided, default to Full Range based on tickSpacing
79
85
  let tLower = tickLower;
@@ -1,3 +1,4 @@
1
+ import { normalizeChainName } from '../utils/chains';
1
2
  import { parseUnits } from 'viem';
2
3
  import * as process from 'process';
3
4
  import crypto from 'crypto';
@@ -7,6 +8,7 @@ import { resolveToken, ERC20_ABI, getTokenMetadata } from '../utils/tokens';
7
8
 
8
9
  export async function prepareRevokeApproval(chainName: ChainName, tokenAddressOrSymbol: string, spenderAddress: `0x${string}`): Promise<string> {
9
10
  try {
11
+ chainName = normalizeChainName(chainName);
10
12
  if (!chainName || !tokenAddressOrSymbol || !spenderAddress) throw new Error("Missing required parameters for revoking approval.");
11
13
  const publicClient = getPublicClient(chainName);
12
14
  const userAddress = await getAddress();
@@ -1,3 +1,4 @@
1
+ import { normalizeChainName } from '../utils/chains';
1
2
  import { parseUnits, formatUnits } from 'viem';
2
3
  import { ChainName, SUPPORTED_CHAIN_NAMES } from '../config';
3
4
  import { getAddress, submitTransaction } from '../utils/vaultClient';
@@ -5,7 +6,8 @@ import { txManager } from '../../agent/transactionManager';
5
6
  import { resolveToken } from '../utils/tokens';
6
7
  import { saveTokenToWhitelist } from '../../utils/userWhitelistManager';
7
8
  import { routeTransaction } from '../aggregator/defiRouter';
8
-
9
+ import { logger } from '../../memory/logger';
10
+ import { loadConfig } from '../../config/parser';
9
11
  export async function prepareSwapToken(
10
12
  chainName: ChainName,
11
13
  fromToken: string,
@@ -16,6 +18,7 @@ export async function prepareSwapToken(
16
18
  slippagePercent?: number | "auto"
17
19
  ): Promise<string> {
18
20
  try {
21
+ chainName = normalizeChainName(chainName);
19
22
  if (!chainName || !fromToken || !toToken || !amountStr) throw new Error("Missing required parameters for swap (chain, tokens, or amount).");
20
23
  const userAddress = await getAddress();
21
24
 
@@ -57,7 +60,20 @@ export async function prepareSwapToken(
57
60
  throw new Error(balanceCheck.message);
58
61
  }
59
62
  // --------------------------------
60
- const slippage = slippagePercent || "auto";
63
+ // Front-to-Back Slippage Architecture
64
+ const userProfile = logger.getUserProfile();
65
+ const maxSlippage = userProfile?.max_slippage || 1.0;
66
+ const config = loadConfig();
67
+ const cfgSlippage = (config.agent as any)?.default_slippage;
68
+
69
+ let finalSlippage = slippagePercent;
70
+ if (finalSlippage === undefined || finalSlippage === null || finalSlippage === "auto") {
71
+ finalSlippage = (cfgSlippage === "auto" || !cfgSlippage) ? 0.5 : parseFloat(cfgSlippage as string);
72
+ }
73
+
74
+ if (typeof finalSlippage !== 'number' || isNaN(finalSlippage)) finalSlippage = 0.5;
75
+ if (finalSlippage > maxSlippage) finalSlippage = maxSlippage;
76
+ const slippage = finalSlippage;
61
77
 
62
78
  const route = await routeTransaction(
63
79
  chainName,
@@ -93,6 +109,7 @@ export async function prepareSwapToken(
93
109
  }
94
110
 
95
111
  export async function executeSwap(chainName: string, details: any, autoApprove: boolean = false): Promise<string> {
112
+ chainName = normalizeChainName(chainName);
96
113
  const payload = {
97
114
  type: 'swap',
98
115
  chainName,
@@ -114,7 +131,7 @@ export const swapTokenToolDefinition = {
114
131
  toToken: { type: "string" },
115
132
  amountStr: { type: "string", description: "The amount to swap" },
116
133
  mode: { type: "string", enum: ["auto", "manual"], default: "auto" },
117
- providerName: { type: "string", enum: ["auto", "1inch", "0x", "lifi", "relay", "openocean", "kyberswap"], default: "auto" },
134
+ providerName: { type: "string", enum: ["auto", "1inch", "0x", "lifi", "relay", "openocean", "kyberswap"], default: "auto", description: "The preferred DEX aggregator or bridge. Use 'auto' to let the system pick the best route." },
118
135
  slippagePercent: { type: "number" }
119
136
  },
120
137
  required: ["chainName", "fromToken", "toToken", "amountStr"],
@@ -1,3 +1,4 @@
1
+ import { normalizeChainName } from '../utils/chains';
1
2
  import { parseEther, parseUnits, encodeFunctionData } from 'viem';
2
3
  import { getPublicClient, getAddress, ChainName, SUPPORTED_CHAIN_NAMES } from '../config';
3
4
  import { txManager } from '../../agent/transactionManager';
@@ -6,6 +7,7 @@ import { submitTransaction } from '../utils/vaultClient';
6
7
 
7
8
  export async function prepareTransfer(chainName: ChainName, toAddress: `0x${string}`, amountStr: string, token?: string): Promise<string> {
8
9
  try {
10
+ chainName = normalizeChainName(chainName);
9
11
  if (!chainName || !toAddress || !amountStr) throw new Error("Missing required parameters for transfer (chain, recipient, or amount).");
10
12
  const publicClient = getPublicClient(chainName);
11
13
  const userAddress = await getAddress();
@@ -1,3 +1,4 @@
1
+ import { normalizeChainName } from '../utils/chains';
1
2
  import { parseUnits } from 'viem';
2
3
  import { getPublicClient, getAddress, ChainName, SUPPORTED_CHAIN_NAMES } from '../config';
3
4
  import { txManager } from '../../agent/transactionManager';
@@ -23,6 +24,7 @@ const VAULT_ABI = [
23
24
 
24
25
  export async function prepareVaultDeposit(chainName: ChainName, protocol: string, vaultAddress: `0x${string}`, tokenAddressOrSymbol: string, amountStr: string): Promise<string> {
25
26
  try {
27
+ chainName = normalizeChainName(chainName);
26
28
  if (!chainName || !vaultAddress || !tokenAddressOrSymbol || !amountStr) throw new Error("Missing protocol/chain/token parameters for DeFi operation.");
27
29
  const publicClient = getPublicClient(chainName);
28
30
  const userAddress = await getAddress();
@@ -15,3 +15,15 @@ export const supportedChains = {
15
15
 
16
16
  export const SUPPORTED_CHAIN_NAMES = Object.keys(supportedChains);
17
17
  export type ChainName = keyof typeof supportedChains;
18
+
19
+ export function normalizeChainName(name: string): ChainName {
20
+ let _c = String(name || "").trim().toLowerCase().replace(/\s+/g, '_');
21
+ if (_c.startsWith('arb_')) _c = _c.replace('arb_', 'arbitrum_');
22
+ else if (_c === 'arb') _c = 'arbitrum';
23
+ else if (_c.startsWith('opt_')) _c = _c.replace('opt_', 'optimism_');
24
+ else if (_c === 'opt') _c = 'optimism';
25
+ else if (_c === 'matic') _c = 'polygon';
26
+ else if (_c === 'eth') _c = 'ethereum';
27
+ else if (_c === 'bnb') _c = 'bsc';
28
+ return _c as ChainName;
29
+ }
@@ -7,7 +7,31 @@ export async function analyzeMarketEngine(chainName: ChainName, tokenAddressOrSy
7
7
  const cleanSymbol = tokenAddressOrSymbol.replace('$', '').toLowerCase();
8
8
  const keys = loadMarketKeys();
9
9
 
10
- // Tier 1 & 2: CoinGecko (Pro if key exists, else Public)
10
+ // Tier 1: CoinMarketCap (Pro if key exists)
11
+ if (keys.cmc_key) {
12
+ try {
13
+ const data = await safeFetchJson<any>(`https://pro-api.coinmarketcap.com/v2/cryptocurrency/quotes/latest?symbol=${cleanSymbol.toUpperCase()}`, {
14
+ headers: { 'X-CMC_PRO_API_KEY': keys.cmc_key }
15
+ });
16
+ const coin = data.data?.[cleanSymbol.toUpperCase()]?.[0];
17
+ if (coin) {
18
+ let report = `📈 **Market Analysis for ${coin.name} (${coin.symbol})** [Global via CoinMarketCap Pro]\n\n`;
19
+ report += `**Price:** $${coin.quote.USD.price.toFixed(6)}\n`;
20
+ report += `**Market Cap:** $${Number(coin.quote.USD.market_cap).toLocaleString()}\n`;
21
+ report += `**24h Volume:** $${Number(coin.quote.USD.volume_24h).toLocaleString()}\n\n`;
22
+ report += `**Price Change:**\n`;
23
+ report += `- 1h: ${coin.quote.USD.percent_change_1h.toFixed(2)}% \n`;
24
+ report += `- 24h: ${coin.quote.USD.percent_change_24h.toFixed(2)}% \n`;
25
+ report += `- 7d: ${coin.quote.USD.percent_change_7d.toFixed(2)}% \n\n`;
26
+ report += `**Rank:** #${coin.cmc_rank}\n`;
27
+ return report;
28
+ }
29
+ } catch (e: any) {
30
+ console.warn("CMC analysis failed, falling back to CoinGecko...", e.message);
31
+ }
32
+ }
33
+
34
+ // Tier 2: CoinGecko (Pro if key exists, else Public)
11
35
  try {
12
36
  const isPro = !!keys.coingecko_key;
13
37
  const baseUrl = isPro ? 'https://pro-api.coingecko.com/api/v3' : 'https://api.coingecko.com/api/v3';
@@ -29,38 +53,8 @@ export async function analyzeMarketEngine(chainName: ChainName, tokenAddressOrSy
29
53
  report += `**Rank:** #${coinData.market_cap_rank || 'N/A'}\n`;
30
54
  return report;
31
55
  }
32
- } catch (e) {
33
- if (keys.cmc_key) {
34
- console.warn("CoinGecko analysis failed, falling back to CMC...", e.message);
35
- } else {
36
- console.warn("CoinGecko analysis failed, falling back to DexScreener...", e.message);
37
- }
38
- }
39
-
40
- // Tier 1 & 2: CoinMarketCap (Pro if key exists)
41
- // Note: CMC doesn't have a truly open public endpoint like CG without keys,
42
- // but if the user provided the key, we prioritize it here.
43
- if (keys.cmc_key) {
44
- try {
45
- const data = await safeFetchJson<any>(`https://pro-api.coinmarketcap.com/v2/cryptocurrency/quotes/latest?symbol=${cleanSymbol.toUpperCase()}`, {
46
- headers: { 'X-CMC_PRO_API_KEY': keys.cmc_key }
47
- });
48
- const coin = data.data?.[cleanSymbol.toUpperCase()]?.[0];
49
- if (coin) {
50
- let report = `📈 **Market Analysis for ${coin.name} (${coin.symbol})** [Global via CoinMarketCap Pro]\n\n`;
51
- report += `**Price:** $${coin.quote.USD.price.toFixed(6)}\n`;
52
- report += `**Market Cap:** $${Number(coin.quote.USD.market_cap).toLocaleString()}\n`;
53
- report += `**24h Volume:** $${Number(coin.quote.USD.volume_24h).toLocaleString()}\n\n`;
54
- report += `**Price Change:**\n`;
55
- report += `- 1h: ${coin.quote.USD.percent_change_1h.toFixed(2)}% \n`;
56
- report += `- 24h: ${coin.quote.USD.percent_change_24h.toFixed(2)}% \n`;
57
- report += `- 7d: ${coin.quote.USD.percent_change_7d.toFixed(2)}% \n\n`;
58
- report += `**Rank:** #${coin.cmc_rank}\n`;
59
- return report;
60
- }
61
- } catch (e) {
62
- console.warn("CMC analysis failed, falling back to DexScreener...", e.message);
63
- }
56
+ } catch (e: any) {
57
+ console.warn("CoinGecko analysis failed, falling back to DexScreener...", e.message);
64
58
  }
65
59
 
66
60
  // Tier 2: Ultimate Fallback Engine: DexScreener Cross-Chain Search