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.
- package/CHANGELOG.md +95 -47
- package/README.md +23 -19
- package/bin/nyxora.mjs +4 -6
- package/dist/launcher.js +44 -8
- package/dist/packages/core/src/agent/bridgeWatcher.js +3 -2
- package/dist/packages/core/src/agent/cronManager.js +2 -2
- package/dist/packages/core/src/agent/llmProvider.js +242 -0
- package/dist/packages/core/src/agent/nyxDaemon.js +97 -0
- package/dist/packages/core/src/agent/osAgent.js +203 -29
- package/dist/packages/core/src/agent/reasoning.js +353 -60
- package/dist/packages/core/src/agent/reasoningScratchpad.js +47 -0
- package/dist/packages/core/src/agent/transactionManager.js +36 -31
- package/dist/packages/core/src/agent/web3Agent.js +263 -37
- package/dist/packages/core/src/cognitive/cognitiveManager.js +63 -10
- package/dist/packages/core/src/config/parser.js +10 -4
- package/dist/packages/core/src/gateway/chat.js +56 -13
- package/dist/packages/core/src/gateway/cli.js +3 -0
- package/dist/packages/core/src/gateway/discordAdapter.js +81 -0
- package/dist/packages/core/src/gateway/server.js +58 -9
- package/dist/packages/core/src/gateway/setup-ml.js +64 -0
- package/dist/packages/core/src/gateway/setup.js +39 -3
- package/dist/packages/core/src/gateway/telegram.js +120 -24
- package/dist/packages/core/src/memory/episodic.js +47 -3
- package/dist/packages/core/src/memory/logger.js +120 -2
- package/dist/packages/core/src/memory/promotionEngine.js +18 -5
- package/dist/packages/core/src/system/agentskills.js +10 -0
- package/dist/packages/core/src/system/plugins/GoogleWorkspacePlugin.js +1 -1
- package/dist/packages/core/src/system/plugins/SystemCorePlugin.js +1 -1
- package/dist/packages/core/src/system/plugins/SystemExternalPlugin.js +1 -1
- package/dist/packages/core/src/system/plugins/SystemPluginInstallerPlugin.js +1 -1
- package/dist/packages/core/src/system/plugins/SystemSocialPlugin.js +1 -1
- package/dist/packages/core/src/system/plugins/SystemWebPlugin.js +1 -1
- package/dist/packages/core/src/system/plugins/SystemWorkspacePlugin.js +3 -3
- package/dist/packages/core/src/system/plugins/createSkill.js +1 -1
- package/dist/packages/core/src/system/skillExtractor.js +16 -5
- package/dist/packages/core/src/system/skills/forgetMemory.js +6 -4
- package/dist/packages/core/src/system/skills/scheduleTask.js +7 -2
- package/dist/packages/core/src/test_mainnet.js +45 -0
- package/dist/packages/core/src/utils/contextSummarizer.js +82 -0
- package/dist/packages/core/src/utils/skillManager.js +1 -1
- package/dist/packages/core/src/utils/streamSimulator.js +85 -0
- package/dist/packages/core/src/web3/aggregator/providers/ArbitrumBridgeProvider.js +28 -11
- package/dist/packages/core/src/web3/aggregator/providers/OpBridgeProvider.js +41 -27
- package/dist/packages/core/src/web3/aggregator/providers/TestnetSwapProvider.js +65 -0
- package/dist/packages/core/src/web3/aggregator/routeSelector.js +7 -1
- package/dist/packages/core/src/web3/plugins/Web3DefiPlugin.js +1 -1
- package/dist/packages/core/src/web3/plugins/Web3MarketPlugin.js +5 -125
- package/dist/packages/core/src/web3/plugins/Web3SecurityPlugin.js +1 -1
- package/dist/packages/core/src/web3/plugins/Web3WalletPlugin.js +1 -1
- package/dist/packages/core/src/web3/skills/bridgeToken.js +19 -4
- package/dist/packages/core/src/web3/skills/checkAddress.js +2 -0
- package/dist/packages/core/src/web3/skills/checkPortfolio.js +22 -2
- package/dist/packages/core/src/web3/skills/checkSecurity.js +2 -0
- package/dist/packages/core/src/web3/skills/confirmPendingTx.js +1 -1
- package/dist/packages/core/src/web3/skills/createLimitOrder.js +15 -1
- package/dist/packages/core/src/web3/skills/customTx.js +3 -0
- package/dist/packages/core/src/web3/skills/defiLending.js +2 -0
- package/dist/packages/core/src/web3/skills/getBalance.js +2 -0
- package/dist/packages/core/src/web3/skills/getPrice.js +134 -27
- package/dist/packages/core/src/web3/skills/getTxHistory.js +2 -0
- package/dist/packages/core/src/web3/skills/marketAnalysis.js +28 -191
- package/dist/packages/core/src/web3/skills/mintNft.js +3 -0
- package/dist/packages/core/src/web3/skills/provideLiquidity.js +16 -12
- package/dist/packages/core/src/web3/skills/revokeApprovals.js +2 -0
- package/dist/packages/core/src/web3/skills/swapToken.js +20 -2
- package/dist/packages/core/src/web3/skills/transfer.js +2 -0
- package/dist/packages/core/src/web3/skills/yieldVault.js +2 -0
- package/dist/packages/core/src/web3/utils/chains.js +19 -0
- package/dist/packages/core/src/web3/utils/marketEngine.js +26 -33
- package/dist/packages/signer/src/NyxoraSigner.js +181 -0
- package/dist/packages/signer/src/index.js +17 -0
- package/dist/packages/signer/src/server.js +25 -161
- package/launcher.ts +38 -9
- package/package.json +6 -2
- package/packages/core/package.json +21 -10
- package/packages/core/src/agent/bridgeWatcher.ts +3 -2
- package/packages/core/src/agent/cronManager.ts +2 -2
- package/packages/core/src/agent/llmProvider.ts +219 -0
- package/packages/core/src/agent/nyxDaemon.ts +104 -0
- package/packages/core/src/agent/osAgent.ts +230 -32
- package/packages/core/src/agent/reasoning.ts +376 -64
- package/packages/core/src/agent/reasoningScratchpad.ts +45 -0
- package/packages/core/src/agent/transactionManager.ts +36 -28
- package/packages/core/src/agent/web3Agent.ts +291 -40
- package/packages/core/src/cognitive/cognitiveManager.ts +65 -10
- package/packages/core/src/cognitive/prompts/web3/market-analysis.md +24 -0
- package/packages/core/src/cognitive/prompts/web3/portfolio-review.md +29 -0
- package/packages/core/src/cognitive/prompts/web3/risk-assessment.md +28 -0
- package/packages/core/src/cognitive/prompts/web3/trade-planning.md +30 -0
- package/packages/core/src/config/parser.ts +15 -4
- package/packages/core/src/gateway/chat.ts +57 -15
- package/packages/core/src/gateway/cli.ts +4 -0
- package/packages/core/src/gateway/discordAdapter.ts +87 -0
- package/packages/core/src/gateway/server.ts +66 -10
- package/packages/core/src/gateway/setup-ml.ts +68 -0
- package/packages/core/src/gateway/setup.ts +41 -3
- package/packages/core/src/gateway/telegram.ts +138 -27
- package/packages/core/src/memory/episodic.ts +64 -3
- package/packages/core/src/memory/logger.ts +142 -2
- package/packages/core/src/memory/promotionEngine.ts +19 -5
- package/packages/core/src/system/agentskills.ts +10 -0
- package/packages/core/src/system/plugins/GoogleWorkspacePlugin.ts +1 -1
- package/packages/core/src/system/plugins/SystemCorePlugin.ts +1 -1
- package/packages/core/src/system/plugins/SystemExternalPlugin.ts +1 -1
- package/packages/core/src/system/plugins/SystemPluginInstallerPlugin.ts +1 -1
- package/packages/core/src/system/plugins/SystemSocialPlugin.ts +1 -1
- package/packages/core/src/system/plugins/SystemWebPlugin.ts +1 -1
- package/packages/core/src/system/plugins/SystemWorkspacePlugin.ts +3 -3
- package/packages/core/src/system/plugins/createSkill.ts +1 -1
- package/packages/core/src/system/skillExtractor.ts +16 -5
- package/packages/core/src/system/skills/forgetMemory.ts +7 -4
- package/packages/core/src/system/skills/scheduleTask.ts +7 -2
- package/packages/core/src/utils/contextSummarizer.ts +100 -0
- package/packages/core/src/utils/skillManager.ts +1 -1
- package/packages/core/src/utils/streamSimulator.ts +88 -0
- package/packages/core/src/web3/aggregator/providers/ArbitrumBridgeProvider.ts +30 -11
- package/packages/core/src/web3/aggregator/providers/OpBridgeProvider.ts +43 -29
- package/packages/core/src/web3/aggregator/routeSelector.ts +6 -1
- package/packages/core/src/web3/plugins/Web3DefiPlugin.ts +1 -1
- package/packages/core/src/web3/plugins/Web3MarketPlugin.ts +6 -125
- package/packages/core/src/web3/plugins/Web3SecurityPlugin.ts +1 -1
- package/packages/core/src/web3/plugins/Web3WalletPlugin.ts +1 -1
- package/packages/core/src/web3/skills/bridgeToken.ts +21 -7
- package/packages/core/src/web3/skills/checkAddress.ts +2 -0
- package/packages/core/src/web3/skills/checkPortfolio.ts +23 -2
- package/packages/core/src/web3/skills/checkSecurity.ts +2 -0
- package/packages/core/src/web3/skills/confirmPendingTx.ts +1 -1
- package/packages/core/src/web3/skills/createLimitOrder.ts +17 -2
- package/packages/core/src/web3/skills/customTx.ts +3 -0
- package/packages/core/src/web3/skills/defiLending.ts +2 -0
- package/packages/core/src/web3/skills/getBalance.ts +2 -0
- package/packages/core/src/web3/skills/getPrice.ts +134 -30
- package/packages/core/src/web3/skills/getTxHistory.ts +2 -0
- package/packages/core/src/web3/skills/marketAnalysis.ts +45 -188
- package/packages/core/src/web3/skills/mintNft.ts +3 -0
- package/packages/core/src/web3/skills/provideLiquidity.ts +16 -10
- package/packages/core/src/web3/skills/revokeApprovals.ts +2 -0
- package/packages/core/src/web3/skills/swapToken.ts +20 -3
- package/packages/core/src/web3/skills/transfer.ts +2 -0
- package/packages/core/src/web3/skills/yieldVault.ts +2 -0
- package/packages/core/src/web3/utils/chains.ts +12 -0
- package/packages/core/src/web3/utils/marketEngine.ts +27 -33
- package/packages/dashboard/dist/assets/index-BTfp141V.js +18 -0
- package/packages/dashboard/dist/assets/index-DK2sTU47.css +1 -0
- package/packages/dashboard/dist/index.html +2 -2
- package/packages/dashboard/package.json +10 -10
- package/packages/mcp-server/dist/server.js +5 -1
- package/packages/mcp-server/package.json +6 -6
- package/packages/mcp-server/src/server.ts +11 -7
- package/packages/policy/package.json +3 -3
- package/packages/signer/package.json +16 -6
- package/packages/signer/src/NyxoraSigner.ts +161 -0
- package/packages/signer/src/index.ts +1 -0
- package/packages/signer/src/server.ts +25 -135
- package/dist/packages/core/src/agent/honchoDaemon.js +0 -91
- package/dist/packages/core/src/cognitive/prompts/autonomous/binance-trading-integration.md +0 -54
- package/dist/packages/core/src/gateway/test.js +0 -15
- package/dist/packages/core/src/web3/Web3DefiPlugin.js +0 -28
- package/dist/packages/core/src/web3/aggregator/aggregatorMainnet.js +0 -260
- package/dist/packages/core/src/web3/aggregator/aggregatorTestnet.js +0 -119
- package/dist/packages/core/src/web3/skills/nativeOpBridge.js +0 -71
- package/packages/core/src/agent/honchoDaemon.ts +0 -96
- package/packages/core/src/cognitive/prompts/autonomous/binance-trading-integration.md +0 -41
- package/packages/core/src/plugin/registry.test.ts +0 -46
- package/packages/core/src/utils/formatter.test.ts +0 -41
- package/packages/dashboard/dist/assets/index-CSoNa5cx.css +0 -1
- 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 (
|
|
12
|
+
// PHASE 1: DATA ROUTING (PROXY TO PYTHON ML ENGINE)
|
|
112
13
|
// ==========================================
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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:
|
|
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
|
-
|
|
177
|
-
|
|
178
|
-
|
|
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
|
-
|
|
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
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
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
|
|
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
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|