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
|
@@ -2,214 +2,51 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.marketAnalysisToolDefinition = void 0;
|
|
4
4
|
exports.analyzeMarket = analyzeMarket;
|
|
5
|
+
const chains_1 = require("../utils/chains");
|
|
5
6
|
const config_1 = require("../config");
|
|
6
7
|
const httpClient_1 = require("../../utils/httpClient");
|
|
7
8
|
const riskIntelligence_1 = require("../utils/riskIntelligence");
|
|
8
|
-
const marketConfigManager_1 = require("../../config/marketConfigManager");
|
|
9
|
-
async function fetchCexData(symbol) {
|
|
10
|
-
try {
|
|
11
|
-
const binance = await (0, httpClient_1.safeFetchJson)(`https://api.binance.com/api/v3/ticker/24hr?symbol=${symbol}USDT`);
|
|
12
|
-
if (binance && binance.lastPrice)
|
|
13
|
-
return { price: parseFloat(binance.lastPrice), vol: parseFloat(binance.quoteVolume), change: parseFloat(binance.priceChangePercent), name: "Binance" };
|
|
14
|
-
}
|
|
15
|
-
catch { }
|
|
16
|
-
try {
|
|
17
|
-
const kucoin = await (0, httpClient_1.safeFetchJson)(`https://api.kucoin.com/api/v1/market/stats?symbol=${symbol}-USDT`);
|
|
18
|
-
if (kucoin && kucoin.data && kucoin.data.last)
|
|
19
|
-
return { price: parseFloat(kucoin.data.last), vol: parseFloat(kucoin.data.volValue), change: parseFloat(kucoin.data.changeRate) * 100, name: "KuCoin" };
|
|
20
|
-
}
|
|
21
|
-
catch { }
|
|
22
|
-
try {
|
|
23
|
-
const mexc = await (0, httpClient_1.safeFetchJson)(`https://api.mexc.com/api/v3/ticker/24hr?symbol=${symbol}USDT`);
|
|
24
|
-
if (mexc && mexc.lastPrice)
|
|
25
|
-
return { price: parseFloat(mexc.lastPrice), vol: parseFloat(mexc.quoteVolume), change: parseFloat(mexc.priceChangePercent), name: "MEXC" };
|
|
26
|
-
}
|
|
27
|
-
catch { }
|
|
28
|
-
return null;
|
|
29
|
-
}
|
|
30
|
-
async function fetchCoinGeckoData(symbol) {
|
|
31
|
-
try {
|
|
32
|
-
const keys = (0, marketConfigManager_1.loadMarketKeys)();
|
|
33
|
-
const isPro = !!keys.coingecko_key;
|
|
34
|
-
const baseUrl = isPro ? 'https://pro-api.coingecko.com/api/v3' : 'https://api.coingecko.com/api/v3';
|
|
35
|
-
const headers = isPro ? { 'x-cg-pro-api-key': keys.coingecko_key } : undefined;
|
|
36
|
-
const searchData = await (0, httpClient_1.safeFetchJson)(`${baseUrl}/search?query=${symbol}`, { headers });
|
|
37
|
-
const foundCoin = searchData.coins?.find((c) => c.symbol.toLowerCase() === symbol.toLowerCase() || c.id === symbol.toLowerCase());
|
|
38
|
-
if (foundCoin) {
|
|
39
|
-
const coinData = await (0, httpClient_1.safeFetchJson)(`${baseUrl}/coins/${foundCoin.id}?localization=false&tickers=false&market_data=true&community_data=false&developer_data=false`, { headers });
|
|
40
|
-
if (coinData && coinData.market_data) {
|
|
41
|
-
return {
|
|
42
|
-
price: coinData.market_data.current_price?.usd || 0,
|
|
43
|
-
mcap: coinData.market_data.market_cap?.usd || 0,
|
|
44
|
-
fdv: coinData.market_data.fully_diluted_valuation?.usd || coinData.market_data.market_cap?.usd || 0,
|
|
45
|
-
vol: coinData.market_data.total_volume?.usd || 0,
|
|
46
|
-
change: coinData.market_data.price_change_percentage_24h || 0,
|
|
47
|
-
name: "CoinGecko"
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
catch { }
|
|
53
|
-
return null;
|
|
54
|
-
}
|
|
55
|
-
async function fetchDexData(query, isCa, chainName) {
|
|
56
|
-
let data;
|
|
57
|
-
if (isCa)
|
|
58
|
-
data = await (0, httpClient_1.safeFetchJson)(`https://api.dexscreener.com/latest/dex/tokens/${query}`);
|
|
59
|
-
else
|
|
60
|
-
data = await (0, httpClient_1.safeFetchJson)(`https://api.dexscreener.com/latest/dex/search?q=${query}`);
|
|
61
|
-
if (data && data.pairs && data.pairs.length > 0) {
|
|
62
|
-
let pairs = data.pairs;
|
|
63
|
-
if (chainName) {
|
|
64
|
-
pairs = pairs.filter((p) => p.chainId?.toLowerCase() === chainName?.toLowerCase());
|
|
65
|
-
if (pairs.length === 0)
|
|
66
|
-
pairs = data.pairs;
|
|
67
|
-
}
|
|
68
|
-
return pairs.sort((a, b) => (b.volume?.h24 || 0) - (a.volume?.h24 || 0))[0];
|
|
69
|
-
}
|
|
70
|
-
return null;
|
|
71
|
-
}
|
|
72
|
-
async function fetchCexMomentum(symbol, currentP) {
|
|
73
|
-
let rsi = null;
|
|
74
|
-
let ma50 = null;
|
|
75
|
-
try {
|
|
76
|
-
const binanceKlines = await (0, httpClient_1.safeFetchJson)(`https://api.binance.com/api/v3/klines?symbol=${symbol}USDT&interval=1d&limit=50`);
|
|
77
|
-
if (binanceKlines && binanceKlines.length > 0) {
|
|
78
|
-
const closes = binanceKlines.map((k) => parseFloat(k[4]));
|
|
79
|
-
const sum = closes.reduce((a, b) => a + b, 0);
|
|
80
|
-
ma50 = sum / closes.length;
|
|
81
|
-
rsi = 55;
|
|
82
|
-
}
|
|
83
|
-
return { ma50, rsi };
|
|
84
|
-
}
|
|
85
|
-
catch (e1) {
|
|
86
|
-
try {
|
|
87
|
-
await (0, httpClient_1.safeFetchJson)(`https://api.kucoin.com/api/v1/market/stats?symbol=${symbol}-USDT`);
|
|
88
|
-
return { ma50: currentP * 0.95, rsi: 50 };
|
|
89
|
-
}
|
|
90
|
-
catch (e2) {
|
|
91
|
-
try {
|
|
92
|
-
await (0, httpClient_1.safeFetchJson)(`https://api.mexc.com/api/v3/ticker/24hr?symbol=${symbol}USDT`);
|
|
93
|
-
return { ma50: currentP * 1.05, rsi: 45 };
|
|
94
|
-
}
|
|
95
|
-
catch (e3) {
|
|
96
|
-
return { ma50: null, rsi: null };
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
9
|
async function analyzeMarket(chainName, tokenAddressOrSymbol) {
|
|
102
10
|
try {
|
|
11
|
+
chainName = (0, chains_1.normalizeChainName)(chainName);
|
|
103
12
|
if (!tokenAddressOrSymbol)
|
|
104
13
|
throw new Error("Token symbol is invalid.");
|
|
105
|
-
const cleanInput = String(tokenAddressOrSymbol || "").replace('$', '').toLowerCase();
|
|
106
|
-
const isAddress = cleanInput.startsWith('0x') && cleanInput.length === 42;
|
|
107
|
-
let officialSymbol = cleanInput.toUpperCase();
|
|
108
|
-
let contractAddress = isAddress ? cleanInput : null;
|
|
109
|
-
let network = chainName || "UNKNOWN";
|
|
110
|
-
let currentPrice = 0;
|
|
111
|
-
let mcapUsd = 0;
|
|
112
|
-
let liquidityUsd = 0;
|
|
113
|
-
let volume24h = 0;
|
|
114
|
-
let priceChange24h = 0;
|
|
115
|
-
let rsi = null;
|
|
116
|
-
let ma50 = null;
|
|
117
|
-
let isCexAsset = false;
|
|
118
14
|
// ==========================================
|
|
119
|
-
// PHASE 1: DATA ROUTING (
|
|
15
|
+
// PHASE 1: DATA ROUTING (PROXY TO PYTHON ML ENGINE)
|
|
120
16
|
// ==========================================
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
officialSymbol = targetPair.baseToken.symbol;
|
|
126
|
-
contractAddress = targetPair.baseToken.address;
|
|
127
|
-
network = targetPair.chainId.toUpperCase();
|
|
128
|
-
currentPrice = parseFloat(targetPair.priceUsd || "0");
|
|
129
|
-
mcapUsd = targetPair.fdv || 0;
|
|
130
|
-
liquidityUsd = targetPair.liquidity?.usd || 0;
|
|
131
|
-
volume24h = targetPair.volume?.h24 || 0;
|
|
132
|
-
priceChange24h = targetPair.priceChange?.h24 || 0;
|
|
133
|
-
}
|
|
134
|
-
else {
|
|
135
|
-
return `[Market Intelligence] Failed to find data for Contract Address ${tokenAddressOrSymbol} on DEX.`;
|
|
136
|
-
}
|
|
137
|
-
// Fetch CEX momentum if available
|
|
138
|
-
const momentum = await fetchCexMomentum(officialSymbol, currentPrice);
|
|
139
|
-
ma50 = momentum.ma50;
|
|
140
|
-
rsi = momentum.rsi;
|
|
17
|
+
console.log(`[Market Intelligence] Delegating analysis for ${tokenAddressOrSymbol} to Python ML Engine...`);
|
|
18
|
+
let mlData;
|
|
19
|
+
try {
|
|
20
|
+
mlData = await (0, httpClient_1.safeFetchJson)(`http://localhost:8000/web3/analyze?query=${tokenAddressOrSymbol}&chain=${chainName}`);
|
|
141
21
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
isCexAsset = true;
|
|
148
|
-
network = `Global CEX/Market`;
|
|
149
|
-
currentPrice = cex ? cex.price : (cgData?.price || 0);
|
|
150
|
-
volume24h = cgData ? cgData.vol : (cex?.vol || 0);
|
|
151
|
-
priceChange24h = cex ? cex.change : (cgData?.change || 0);
|
|
152
|
-
// Use original CoinGecko FDV if available, else proxy from CEX volume
|
|
153
|
-
mcapUsd = cgData ? cgData.fdv : (volume24h * 10);
|
|
154
|
-
// Estimate institutional liquidity (CoinGecko lacks deep liquidity, proxying as 10% of mcap)
|
|
155
|
-
liquidityUsd = cgData ? cgData.fdv * 0.1 : (volume24h * 2);
|
|
156
|
-
const momentum = await fetchCexMomentum(officialSymbol, currentPrice);
|
|
157
|
-
ma50 = momentum.ma50;
|
|
158
|
-
rsi = momentum.rsi;
|
|
159
|
-
}
|
|
160
|
-
else {
|
|
161
|
-
// Fallback to DEX if CEX data is unavailable
|
|
162
|
-
const targetPair = await fetchDexData(cleanInput, false, chainName);
|
|
163
|
-
if (targetPair) {
|
|
164
|
-
officialSymbol = targetPair.baseToken.symbol;
|
|
165
|
-
contractAddress = targetPair.baseToken.address;
|
|
166
|
-
network = targetPair.chainId.toUpperCase();
|
|
167
|
-
currentPrice = parseFloat(targetPair.priceUsd || "0");
|
|
168
|
-
mcapUsd = targetPair.fdv || 0;
|
|
169
|
-
liquidityUsd = targetPair.liquidity?.usd || 0;
|
|
170
|
-
volume24h = targetPair.volume?.h24 || 0;
|
|
171
|
-
priceChange24h = targetPair.priceChange?.h24 || 0;
|
|
172
|
-
}
|
|
173
|
-
else {
|
|
174
|
-
return `[Market Intelligence] Failed to find market data for symbol ${officialSymbol} on both CEX and DEX.`;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
return `[System Error] Failed to reach Python ML Engine. Make sure the daemon is running (Error: ${error.message})`;
|
|
24
|
+
}
|
|
25
|
+
if (!mlData || mlData.detail) {
|
|
26
|
+
return `[Market Intelligence] Failed to find data for ${tokenAddressOrSymbol} on DEX or CEX.`;
|
|
177
27
|
}
|
|
28
|
+
const { officialSymbol, contractAddress, network, currentPrice, mcapUsd, liquidityUsd, volume24h, priceChange24h, rsi, ma50, isCexAsset } = mlData;
|
|
178
29
|
// ==========================================
|
|
179
|
-
// PHASE 2:
|
|
30
|
+
// PHASE 2: HEALTH & RISK SCORING (NODE.JS)
|
|
180
31
|
// ==========================================
|
|
32
|
+
// Dummy TVL and concentration for now, Python can augment this later
|
|
181
33
|
let tvlChange7d = null;
|
|
34
|
+
let top10HoldersPercent = 45; // Default medium risk
|
|
35
|
+
if (mcapUsd > 100000000)
|
|
36
|
+
top10HoldersPercent = 15;
|
|
37
|
+
else if (mcapUsd < 500000)
|
|
38
|
+
top10HoldersPercent = 85;
|
|
39
|
+
let healthResult = {
|
|
40
|
+
liquidityScore: 5.0, smartMoneyScore: 5.0, concentrationScore: 5.0, momentumScore: 5.0, overallScore: 5.0
|
|
41
|
+
};
|
|
182
42
|
try {
|
|
183
|
-
|
|
184
|
-
if (llamaData && llamaData.tvl) {
|
|
185
|
-
const tvlList = llamaData.tvl;
|
|
186
|
-
if (tvlList.length > 7) {
|
|
187
|
-
const todayTvl = tvlList[tvlList.length - 1].totalLiquidityUSD;
|
|
188
|
-
const weekAgoTvl = tvlList[tvlList.length - 8].totalLiquidityUSD;
|
|
189
|
-
if (weekAgoTvl > 0)
|
|
190
|
-
tvlChange7d = ((todayTvl - weekAgoTvl) / weekAgoTvl) * 100;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
43
|
+
healthResult = (0, riskIntelligence_1.generateMarketHealthReport)(liquidityUsd, mcapUsd, tvlChange7d, volume24h, priceChange24h, top10HoldersPercent, rsi, currentPrice, ma50);
|
|
193
44
|
}
|
|
194
|
-
catch {
|
|
195
|
-
|
|
196
|
-
// PHASE 3: ETHERSCAN RPC (Holder Concentration)
|
|
197
|
-
// ==========================================
|
|
198
|
-
let top10HoldersPercent = null;
|
|
199
|
-
if (contractAddress || isCexAsset) {
|
|
200
|
-
if (mcapUsd > 100000000)
|
|
201
|
-
top10HoldersPercent = 15; // Low risk
|
|
202
|
-
else if (mcapUsd < 500000)
|
|
203
|
-
top10HoldersPercent = 85; // High risk (Degen)
|
|
204
|
-
else
|
|
205
|
-
top10HoldersPercent = 45; // Medium risk
|
|
45
|
+
catch (e) {
|
|
46
|
+
console.warn(`[Market Intelligence] Failed to generate deep risk report: ${e.message}`);
|
|
206
47
|
}
|
|
207
48
|
// ==========================================
|
|
208
|
-
// PHASE
|
|
209
|
-
// ==========================================
|
|
210
|
-
const healthResult = (0, riskIntelligence_1.generateMarketHealthReport)(liquidityUsd, mcapUsd, tvlChange7d, volume24h, priceChange24h, top10HoldersPercent, rsi, currentPrice, ma50);
|
|
211
|
-
// ==========================================
|
|
212
|
-
// PHASE 5: CONTEXT ASSEMBLY FOR LLM
|
|
49
|
+
// PHASE 3: CONTEXT ASSEMBLY FOR LLM
|
|
213
50
|
// ==========================================
|
|
214
51
|
let report = `📊 **Market Intelligence Report: ${officialSymbol}**\n`;
|
|
215
52
|
report += `CA: \`${contractAddress || 'N/A'}\` | Network: ${network}\n\n`;
|
|
@@ -233,7 +70,7 @@ exports.marketAnalysisToolDefinition = {
|
|
|
233
70
|
type: "function",
|
|
234
71
|
function: {
|
|
235
72
|
name: "analyze_market",
|
|
236
|
-
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.",
|
|
73
|
+
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'.",
|
|
237
74
|
parameters: {
|
|
238
75
|
type: "object",
|
|
239
76
|
properties: {
|
|
@@ -36,11 +36,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.mintNftToolDefinition = void 0;
|
|
37
37
|
exports.prepareMintNft = prepareMintNft;
|
|
38
38
|
exports.executeMintNft = executeMintNft;
|
|
39
|
+
const chains_1 = require("../utils/chains");
|
|
39
40
|
const viem_1 = require("viem");
|
|
40
41
|
const config_1 = require("../config");
|
|
41
42
|
const transactionManager_1 = require("../../agent/transactionManager");
|
|
42
43
|
async function prepareMintNft(chainName, contractAddress, functionSignature, argsStr, valueEth = "0") {
|
|
43
44
|
try {
|
|
45
|
+
chainName = (0, chains_1.normalizeChainName)(chainName);
|
|
44
46
|
if (!chainName || !contractAddress || !functionSignature)
|
|
45
47
|
throw new Error("Missing required parameters to mint NFT.");
|
|
46
48
|
const publicClient = (0, config_1.getPublicClient)(chainName);
|
|
@@ -112,6 +114,7 @@ async function prepareMintNft(chainName, contractAddress, functionSignature, arg
|
|
|
112
114
|
const vaultClient_1 = require("../utils/vaultClient");
|
|
113
115
|
async function executeMintNft(chainName, params, autoApprove = false) {
|
|
114
116
|
try {
|
|
117
|
+
chainName = (0, chains_1.normalizeChainName)(chainName);
|
|
115
118
|
const { contractAddress, dataHex, amountStr, valueWei } = params;
|
|
116
119
|
const payload = {
|
|
117
120
|
type: 'mint',
|
|
@@ -35,6 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.provideLiquidityToolDefinition = void 0;
|
|
37
37
|
exports.prepareProvideLiquidity = prepareProvideLiquidity;
|
|
38
|
+
const chains_1 = require("../utils/chains");
|
|
38
39
|
const viem_1 = require("viem");
|
|
39
40
|
const config_1 = require("../config");
|
|
40
41
|
const transactionManager_1 = require("../../agent/transactionManager");
|
|
@@ -83,23 +84,26 @@ const POSITION_MANAGERS = {
|
|
|
83
84
|
bsc: "0x46A15B0b27311cedF172AB29E4f4766fbE7F4364" // PancakeSwap V3 Position Manager
|
|
84
85
|
};
|
|
85
86
|
const parser_1 = require("../../config/parser");
|
|
87
|
+
const logger_1 = require("../../memory/logger");
|
|
86
88
|
async function prepareProvideLiquidity(chainName, token0AddressOrSymbol, token1AddressOrSymbol, amount0Str, amount1Str, feeTier, tickLower, tickUpper, slippagePercent) {
|
|
87
89
|
try {
|
|
90
|
+
chainName = (0, chains_1.normalizeChainName)(chainName);
|
|
88
91
|
if (!chainName || !token0AddressOrSymbol || !token1AddressOrSymbol || !amount0Str || !amount1Str)
|
|
89
92
|
throw new Error("Missing protocol/chain/token parameters for DeFi operation.");
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
actualSlippage = 0.5;
|
|
99
|
-
}
|
|
93
|
+
// Front-to-Back Slippage Architecture
|
|
94
|
+
const userProfile = logger_1.logger.getUserProfile();
|
|
95
|
+
const maxSlippage = userProfile?.max_slippage || 1.0;
|
|
96
|
+
const config = (0, parser_1.loadConfig)();
|
|
97
|
+
const cfgSlippage = config.agent?.default_slippage;
|
|
98
|
+
let finalSlippage = slippagePercent;
|
|
99
|
+
if (finalSlippage === undefined || finalSlippage === null || finalSlippage === "auto") {
|
|
100
|
+
finalSlippage = (cfgSlippage === "auto" || !cfgSlippage) ? 0.5 : parseFloat(cfgSlippage);
|
|
100
101
|
}
|
|
101
|
-
if (typeof
|
|
102
|
-
|
|
102
|
+
if (typeof finalSlippage !== 'number' || isNaN(finalSlippage))
|
|
103
|
+
finalSlippage = 0.5;
|
|
104
|
+
if (finalSlippage > maxSlippage)
|
|
105
|
+
finalSlippage = maxSlippage;
|
|
106
|
+
let actualSlippage = finalSlippage;
|
|
103
107
|
// If ticks are not provided, default to Full Range based on tickSpacing
|
|
104
108
|
let tLower = tickLower;
|
|
105
109
|
let tUpper = tickUpper;
|
|
@@ -36,11 +36,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.revokeApprovalToolDefinition = void 0;
|
|
37
37
|
exports.prepareRevokeApproval = prepareRevokeApproval;
|
|
38
38
|
exports.executeRevokeApproval = executeRevokeApproval;
|
|
39
|
+
const chains_1 = require("../utils/chains");
|
|
39
40
|
const config_1 = require("../config");
|
|
40
41
|
const transactionManager_1 = require("../../agent/transactionManager");
|
|
41
42
|
const tokens_1 = require("../utils/tokens");
|
|
42
43
|
async function prepareRevokeApproval(chainName, tokenAddressOrSymbol, spenderAddress) {
|
|
43
44
|
try {
|
|
45
|
+
chainName = (0, chains_1.normalizeChainName)(chainName);
|
|
44
46
|
if (!chainName || !tokenAddressOrSymbol || !spenderAddress)
|
|
45
47
|
throw new Error("Missing required parameters for revoking approval.");
|
|
46
48
|
const publicClient = (0, config_1.getPublicClient)(chainName);
|
|
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.swapTokenToolDefinition = void 0;
|
|
37
37
|
exports.prepareSwapToken = prepareSwapToken;
|
|
38
38
|
exports.executeSwap = executeSwap;
|
|
39
|
+
const chains_1 = require("../utils/chains");
|
|
39
40
|
const viem_1 = require("viem");
|
|
40
41
|
const config_1 = require("../config");
|
|
41
42
|
const vaultClient_1 = require("../utils/vaultClient");
|
|
@@ -43,8 +44,11 @@ const transactionManager_1 = require("../../agent/transactionManager");
|
|
|
43
44
|
const tokens_1 = require("../utils/tokens");
|
|
44
45
|
const userWhitelistManager_1 = require("../../utils/userWhitelistManager");
|
|
45
46
|
const defiRouter_1 = require("../aggregator/defiRouter");
|
|
47
|
+
const logger_1 = require("../../memory/logger");
|
|
48
|
+
const parser_1 = require("../../config/parser");
|
|
46
49
|
async function prepareSwapToken(chainName, fromToken, toToken, amountStr, mode = "auto", providerName = "auto", slippagePercent) {
|
|
47
50
|
try {
|
|
51
|
+
chainName = (0, chains_1.normalizeChainName)(chainName);
|
|
48
52
|
if (!chainName || !fromToken || !toToken || !amountStr)
|
|
49
53
|
throw new Error("Missing required parameters for swap (chain, tokens, or amount).");
|
|
50
54
|
const userAddress = await (0, vaultClient_1.getAddress)();
|
|
@@ -82,7 +86,20 @@ async function prepareSwapToken(chainName, fromToken, toToken, amountStr, mode =
|
|
|
82
86
|
throw new Error(balanceCheck.message);
|
|
83
87
|
}
|
|
84
88
|
// --------------------------------
|
|
85
|
-
|
|
89
|
+
// Front-to-Back Slippage Architecture
|
|
90
|
+
const userProfile = logger_1.logger.getUserProfile();
|
|
91
|
+
const maxSlippage = userProfile?.max_slippage || 1.0;
|
|
92
|
+
const config = (0, parser_1.loadConfig)();
|
|
93
|
+
const cfgSlippage = config.agent?.default_slippage;
|
|
94
|
+
let finalSlippage = slippagePercent;
|
|
95
|
+
if (finalSlippage === undefined || finalSlippage === null || finalSlippage === "auto") {
|
|
96
|
+
finalSlippage = (cfgSlippage === "auto" || !cfgSlippage) ? 0.5 : parseFloat(cfgSlippage);
|
|
97
|
+
}
|
|
98
|
+
if (typeof finalSlippage !== 'number' || isNaN(finalSlippage))
|
|
99
|
+
finalSlippage = 0.5;
|
|
100
|
+
if (finalSlippage > maxSlippage)
|
|
101
|
+
finalSlippage = maxSlippage;
|
|
102
|
+
const slippage = finalSlippage;
|
|
86
103
|
const route = await (0, defiRouter_1.routeTransaction)(chainName, chainName, fromTokenAddress, toTokenAddress, amountWei, amountStr, userAddress, slippage, providerName // BUG #5 Fix: Pass providerName down to router
|
|
87
104
|
);
|
|
88
105
|
const tx = transactionManager_1.txManager.createPendingTransaction('swap', chainName, {
|
|
@@ -106,6 +123,7 @@ async function prepareSwapToken(chainName, fromToken, toToken, amountStr, mode =
|
|
|
106
123
|
}
|
|
107
124
|
}
|
|
108
125
|
async function executeSwap(chainName, details, autoApprove = false) {
|
|
126
|
+
chainName = (0, chains_1.normalizeChainName)(chainName);
|
|
109
127
|
const payload = {
|
|
110
128
|
type: 'swap',
|
|
111
129
|
chainName,
|
|
@@ -127,7 +145,7 @@ exports.swapTokenToolDefinition = {
|
|
|
127
145
|
toToken: { type: "string" },
|
|
128
146
|
amountStr: { type: "string", description: "The amount to swap" },
|
|
129
147
|
mode: { type: "string", enum: ["auto", "manual"], default: "auto" },
|
|
130
|
-
providerName: { type: "string", enum: ["auto", "1inch", "0x", "lifi", "relay", "openocean", "kyberswap"], default: "auto" },
|
|
148
|
+
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." },
|
|
131
149
|
slippagePercent: { type: "number" }
|
|
132
150
|
},
|
|
133
151
|
required: ["chainName", "fromToken", "toToken", "amountStr"],
|
|
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.transferToolDefinition = void 0;
|
|
37
37
|
exports.prepareTransfer = prepareTransfer;
|
|
38
38
|
exports.executeTransfer = executeTransfer;
|
|
39
|
+
const chains_1 = require("../utils/chains");
|
|
39
40
|
const viem_1 = require("viem");
|
|
40
41
|
const config_1 = require("../config");
|
|
41
42
|
const transactionManager_1 = require("../../agent/transactionManager");
|
|
@@ -43,6 +44,7 @@ const tokens_1 = require("../utils/tokens");
|
|
|
43
44
|
const vaultClient_1 = require("../utils/vaultClient");
|
|
44
45
|
async function prepareTransfer(chainName, toAddress, amountStr, token) {
|
|
45
46
|
try {
|
|
47
|
+
chainName = (0, chains_1.normalizeChainName)(chainName);
|
|
46
48
|
if (!chainName || !toAddress || !amountStr)
|
|
47
49
|
throw new Error("Missing required parameters for transfer (chain, recipient, or amount).");
|
|
48
50
|
const publicClient = (0, config_1.getPublicClient)(chainName);
|
|
@@ -35,6 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.vaultDepositToolDefinition = void 0;
|
|
37
37
|
exports.prepareVaultDeposit = prepareVaultDeposit;
|
|
38
|
+
const chains_1 = require("../utils/chains");
|
|
38
39
|
const viem_1 = require("viem");
|
|
39
40
|
const config_1 = require("../config");
|
|
40
41
|
const transactionManager_1 = require("../../agent/transactionManager");
|
|
@@ -58,6 +59,7 @@ const VAULT_ABI = [
|
|
|
58
59
|
];
|
|
59
60
|
async function prepareVaultDeposit(chainName, protocol, vaultAddress, tokenAddressOrSymbol, amountStr) {
|
|
60
61
|
try {
|
|
62
|
+
chainName = (0, chains_1.normalizeChainName)(chainName);
|
|
61
63
|
if (!chainName || !vaultAddress || !tokenAddressOrSymbol || !amountStr)
|
|
62
64
|
throw new Error("Missing protocol/chain/token parameters for DeFi operation.");
|
|
63
65
|
const publicClient = (0, config_1.getPublicClient)(chainName);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SUPPORTED_CHAIN_NAMES = exports.supportedChains = void 0;
|
|
4
|
+
exports.normalizeChainName = normalizeChainName;
|
|
4
5
|
const chains_1 = require("viem/chains");
|
|
5
6
|
exports.supportedChains = {
|
|
6
7
|
ethereum: chains_1.mainnet,
|
|
@@ -15,3 +16,21 @@ exports.supportedChains = {
|
|
|
15
16
|
optimism_sepolia: chains_1.optimismSepolia,
|
|
16
17
|
};
|
|
17
18
|
exports.SUPPORTED_CHAIN_NAMES = Object.keys(exports.supportedChains);
|
|
19
|
+
function normalizeChainName(name) {
|
|
20
|
+
let _c = String(name || "").trim().toLowerCase().replace(/\s+/g, '_');
|
|
21
|
+
if (_c.startsWith('arb_'))
|
|
22
|
+
_c = _c.replace('arb_', 'arbitrum_');
|
|
23
|
+
else if (_c === 'arb')
|
|
24
|
+
_c = 'arbitrum';
|
|
25
|
+
else if (_c.startsWith('opt_'))
|
|
26
|
+
_c = _c.replace('opt_', 'optimism_');
|
|
27
|
+
else if (_c === 'opt')
|
|
28
|
+
_c = 'optimism';
|
|
29
|
+
else if (_c === 'matic')
|
|
30
|
+
_c = 'polygon';
|
|
31
|
+
else if (_c === 'eth')
|
|
32
|
+
_c = 'ethereum';
|
|
33
|
+
else if (_c === 'bnb')
|
|
34
|
+
_c = 'bsc';
|
|
35
|
+
return _c;
|
|
36
|
+
}
|
|
@@ -7,38 +7,7 @@ const httpClient_1 = require("../../utils/httpClient");
|
|
|
7
7
|
async function analyzeMarketEngine(chainName, tokenAddressOrSymbol) {
|
|
8
8
|
const cleanSymbol = tokenAddressOrSymbol.replace('$', '').toLowerCase();
|
|
9
9
|
const keys = (0, marketConfigManager_1.loadMarketKeys)();
|
|
10
|
-
// Tier 1
|
|
11
|
-
try {
|
|
12
|
-
const isPro = !!keys.coingecko_key;
|
|
13
|
-
const baseUrl = isPro ? 'https://pro-api.coingecko.com/api/v3' : 'https://api.coingecko.com/api/v3';
|
|
14
|
-
const headers = isPro ? { 'x-cg-pro-api-key': keys.coingecko_key } : undefined;
|
|
15
|
-
const searchData = await (0, httpClient_1.safeFetchJson)(`${baseUrl}/search?query=${cleanSymbol}`, { headers });
|
|
16
|
-
const foundCoin = searchData.coins?.find((c) => c.symbol.toLowerCase() === cleanSymbol || c.id === cleanSymbol);
|
|
17
|
-
if (foundCoin) {
|
|
18
|
-
const coinData = await (0, httpClient_1.safeFetchJson)(`${baseUrl}/coins/${foundCoin.id}`, { headers });
|
|
19
|
-
let report = `📈 **Market Analysis for ${coinData.name} (${coinData.symbol.toUpperCase()})** [Global via CoinGecko ${isPro ? 'Pro' : 'Public'}]\n\n`;
|
|
20
|
-
report += `**Price:** $${coinData.market_data?.current_price?.usd || 0}\n`;
|
|
21
|
-
report += `**Market Cap:** $${Number(coinData.market_data?.market_cap?.usd || 0).toLocaleString()}\n`;
|
|
22
|
-
report += `**24h Volume:** $${Number(coinData.market_data?.total_volume?.usd || 0).toLocaleString()}\n\n`;
|
|
23
|
-
report += `**Price Change:**\n`;
|
|
24
|
-
report += `- 1h: ${coinData.market_data?.price_change_percentage_1h_in_currency?.usd?.toFixed(2) || 0}% \n`;
|
|
25
|
-
report += `- 24h: ${coinData.market_data?.price_change_percentage_24h?.toFixed(2) || 0}% \n`;
|
|
26
|
-
report += `- 7d: ${coinData.market_data?.price_change_percentage_7d?.toFixed(2) || 0}% \n\n`;
|
|
27
|
-
report += `**Rank:** #${coinData.market_cap_rank || 'N/A'}\n`;
|
|
28
|
-
return report;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
catch (e) {
|
|
32
|
-
if (keys.cmc_key) {
|
|
33
|
-
console.warn("CoinGecko analysis failed, falling back to CMC...", e.message);
|
|
34
|
-
}
|
|
35
|
-
else {
|
|
36
|
-
console.warn("CoinGecko analysis failed, falling back to DexScreener...", e.message);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
// Tier 1 & 2: CoinMarketCap (Pro if key exists)
|
|
40
|
-
// Note: CMC doesn't have a truly open public endpoint like CG without keys,
|
|
41
|
-
// but if the user provided the key, we prioritize it here.
|
|
10
|
+
// Tier 1: CoinMarketCap (Pro if key exists)
|
|
42
11
|
if (keys.cmc_key) {
|
|
43
12
|
try {
|
|
44
13
|
const data = await (0, httpClient_1.safeFetchJson)(`https://pro-api.coinmarketcap.com/v2/cryptocurrency/quotes/latest?symbol=${cleanSymbol.toUpperCase()}`, {
|
|
@@ -59,9 +28,33 @@ async function analyzeMarketEngine(chainName, tokenAddressOrSymbol) {
|
|
|
59
28
|
}
|
|
60
29
|
}
|
|
61
30
|
catch (e) {
|
|
62
|
-
console.warn("CMC analysis failed, falling back to
|
|
31
|
+
console.warn("CMC analysis failed, falling back to CoinGecko...", e.message);
|
|
63
32
|
}
|
|
64
33
|
}
|
|
34
|
+
// Tier 2: CoinGecko (Pro if key exists, else Public)
|
|
35
|
+
try {
|
|
36
|
+
const isPro = !!keys.coingecko_key;
|
|
37
|
+
const baseUrl = isPro ? 'https://pro-api.coingecko.com/api/v3' : 'https://api.coingecko.com/api/v3';
|
|
38
|
+
const headers = isPro ? { 'x-cg-pro-api-key': keys.coingecko_key } : undefined;
|
|
39
|
+
const searchData = await (0, httpClient_1.safeFetchJson)(`${baseUrl}/search?query=${cleanSymbol}`, { headers });
|
|
40
|
+
const foundCoin = searchData.coins?.find((c) => c.symbol.toLowerCase() === cleanSymbol || c.id === cleanSymbol);
|
|
41
|
+
if (foundCoin) {
|
|
42
|
+
const coinData = await (0, httpClient_1.safeFetchJson)(`${baseUrl}/coins/${foundCoin.id}`, { headers });
|
|
43
|
+
let report = `📈 **Market Analysis for ${coinData.name} (${coinData.symbol.toUpperCase()})** [Global via CoinGecko ${isPro ? 'Pro' : 'Public'}]\n\n`;
|
|
44
|
+
report += `**Price:** $${coinData.market_data?.current_price?.usd || 0}\n`;
|
|
45
|
+
report += `**Market Cap:** $${Number(coinData.market_data?.market_cap?.usd || 0).toLocaleString()}\n`;
|
|
46
|
+
report += `**24h Volume:** $${Number(coinData.market_data?.total_volume?.usd || 0).toLocaleString()}\n\n`;
|
|
47
|
+
report += `**Price Change:**\n`;
|
|
48
|
+
report += `- 1h: ${coinData.market_data?.price_change_percentage_1h_in_currency?.usd?.toFixed(2) || 0}% \n`;
|
|
49
|
+
report += `- 24h: ${coinData.market_data?.price_change_percentage_24h?.toFixed(2) || 0}% \n`;
|
|
50
|
+
report += `- 7d: ${coinData.market_data?.price_change_percentage_7d?.toFixed(2) || 0}% \n\n`;
|
|
51
|
+
report += `**Rank:** #${coinData.market_cap_rank || 'N/A'}\n`;
|
|
52
|
+
return report;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch (e) {
|
|
56
|
+
console.warn("CoinGecko analysis failed, falling back to DexScreener...", e.message);
|
|
57
|
+
}
|
|
65
58
|
// Tier 2: Ultimate Fallback Engine: DexScreener Cross-Chain Search
|
|
66
59
|
let query = tokenAddressOrSymbol;
|
|
67
60
|
try {
|