@elizaos/plugin-wallet 2.0.0-beta.1
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/LICENSE +21 -0
- package/README.md +64 -0
- package/auto-enable.ts +76 -0
- package/dist/LpManagementService-BWrQ5-cO.mjs +353 -0
- package/dist/MockLpService-D_Apn4Fd.mjs +99 -0
- package/dist/aerodrome-CfnESC32.mjs +890 -0
- package/dist/chunk-hT5z_Zn9.mjs +35 -0
- package/dist/index.d.mts +34727 -0
- package/dist/index.mjs +21590 -0
- package/dist/lib/server-wallet-trade.d.mts +34 -0
- package/dist/lib/server-wallet-trade.mjs +306 -0
- package/dist/meteora-BPX39hZo.mjs +22640 -0
- package/dist/orca-Bybp1HXO.mjs +249 -0
- package/dist/pancakeswp-CkEXlXti.mjs +604 -0
- package/dist/plugin-ZO_MTyd0.mjs +529 -0
- package/dist/raydium-rfaM9yEf.mjs +539 -0
- package/dist/sdk/index.d.mts +32492 -0
- package/dist/sdk/index.mjs +6415 -0
- package/dist/types-D5252NZk.mjs +487 -0
- package/dist/uniswap-CReXgXVN.mjs +573 -0
- package/dist/wallet-action.d.mts +6 -0
- package/dist/wallet-action.mjs +820 -0
- package/package.json +152 -0
- package/src/actions/failure-codes.ts +79 -0
- package/src/actions/index.ts +1 -0
- package/src/analytics/birdeye/actions/wallet-search-address.ts +9 -0
- package/src/analytics/birdeye/birdeye-task.ts +175 -0
- package/src/analytics/birdeye/birdeye.ts +813 -0
- package/src/analytics/birdeye/constants.ts +74 -0
- package/src/analytics/birdeye/providers/agent-portfolio-provider.ts +18 -0
- package/src/analytics/birdeye/providers/market.ts +227 -0
- package/src/analytics/birdeye/providers/portfolio-factory.test.ts +138 -0
- package/src/analytics/birdeye/providers/portfolio-factory.ts +252 -0
- package/src/analytics/birdeye/providers/trending.ts +365 -0
- package/src/analytics/birdeye/providers/wallet.ts +14 -0
- package/src/analytics/birdeye/search-category.test.ts +207 -0
- package/src/analytics/birdeye/search-category.ts +506 -0
- package/src/analytics/birdeye/service.ts +992 -0
- package/src/analytics/birdeye/tasks/birdeye.ts +232 -0
- package/src/analytics/birdeye/types/api/common.ts +305 -0
- package/src/analytics/birdeye/types/api/defi.ts +220 -0
- package/src/analytics/birdeye/types/api/pair.ts +200 -0
- package/src/analytics/birdeye/types/api/search.ts +86 -0
- package/src/analytics/birdeye/types/api/token.ts +635 -0
- package/src/analytics/birdeye/types/api/trader.ts +76 -0
- package/src/analytics/birdeye/types/api/wallet.ts +181 -0
- package/src/analytics/birdeye/types/shared.ts +106 -0
- package/src/analytics/birdeye/utils.ts +700 -0
- package/src/analytics/dexscreener/errors.ts +28 -0
- package/src/analytics/dexscreener/index.ts +3 -0
- package/src/analytics/dexscreener/search-category.test.ts +49 -0
- package/src/analytics/dexscreener/search-category.ts +42 -0
- package/src/analytics/dexscreener/service.ts +595 -0
- package/src/analytics/dexscreener/types.ts +128 -0
- package/src/analytics/lpinfo/index.d.ts +7 -0
- package/src/analytics/lpinfo/index.ts +52 -0
- package/src/analytics/lpinfo/kamino/README.md +102 -0
- package/src/analytics/lpinfo/kamino/index.ts +24 -0
- package/src/analytics/lpinfo/kamino/providers/kaminoLiquidityProvider.ts +422 -0
- package/src/analytics/lpinfo/kamino/providers/kaminoPoolProvider.ts +365 -0
- package/src/analytics/lpinfo/kamino/providers/kaminoProvider.ts +496 -0
- package/src/analytics/lpinfo/kamino/services/kaminoLiquidityService.ts +1123 -0
- package/src/analytics/lpinfo/kamino/services/kaminoService.ts +758 -0
- package/src/analytics/lpinfo/steer/README.md +169 -0
- package/src/analytics/lpinfo/steer/index.ts +23 -0
- package/src/analytics/lpinfo/steer/providers/steerLiquidityProvider.ts +544 -0
- package/src/analytics/lpinfo/steer/services/steerLiquidityService.ts +1690 -0
- package/src/analytics/lpinfo/steer/steer-display-types.ts +99 -0
- package/src/analytics/news/index.ts +52 -0
- package/src/analytics/news/interfaces/types.ts +222 -0
- package/src/analytics/news/providers/defiNewsProvider.ts +734 -0
- package/src/analytics/news/services/newsDataService.ts +332 -0
- package/src/analytics/news/utils/formatters.ts +151 -0
- package/src/analytics/token-info/action.ts +240 -0
- package/src/analytics/token-info/index.ts +3 -0
- package/src/analytics/token-info/params.ts +215 -0
- package/src/analytics/token-info/providers.ts +681 -0
- package/src/analytics/token-info/service.ts +168 -0
- package/src/analytics/token-info/types.ts +74 -0
- package/src/audit/audit-log.ts +45 -0
- package/src/browser-shim/build-shim.ts +123 -0
- package/src/browser-shim/index.ts +5 -0
- package/src/browser-shim/shim.template.js +563 -0
- package/src/chains/evm/.github/workflows/npm-deploy.yml +112 -0
- package/src/chains/evm/LICENSE +21 -0
- package/src/chains/evm/README.md +106 -0
- package/src/chains/evm/actions/helpers.ts +147 -0
- package/src/chains/evm/actions/swap.ts +839 -0
- package/src/chains/evm/actions/transfer.ts +254 -0
- package/src/chains/evm/biome.json +61 -0
- package/src/chains/evm/bridge-router.ts +660 -0
- package/src/chains/evm/build.ts +89 -0
- package/src/chains/evm/chain-handler.ts +416 -0
- package/src/chains/evm/constants.ts +23 -0
- package/src/chains/evm/contracts/artifacts/OZGovernor.json +1707 -0
- package/src/chains/evm/contracts/artifacts/TimelockController.json +1007 -0
- package/src/chains/evm/contracts/artifacts/VoteToken.json +895 -0
- package/src/chains/evm/dex/aerodrome/index.ts +34 -0
- package/src/chains/evm/dex/aerodrome/services/AerodromeLpService.ts +558 -0
- package/src/chains/evm/dex/aerodrome/types.ts +318 -0
- package/src/chains/evm/dex/pancakeswp/index.ts +35 -0
- package/src/chains/evm/dex/pancakeswp/services/PancakeSwapV3LpService.ts +743 -0
- package/src/chains/evm/dex/pancakeswp/types.ts +65 -0
- package/src/chains/evm/dex/uniswap/index.ts +35 -0
- package/src/chains/evm/dex/uniswap/services/UniswapV3LpService.ts +759 -0
- package/src/chains/evm/dex/uniswap/types.ts +390 -0
- package/src/chains/evm/generated/specs/spec-helpers.ts +73 -0
- package/src/chains/evm/generated/specs/specs.ts +151 -0
- package/src/chains/evm/gov-router.ts +250 -0
- package/src/chains/evm/index.browser.ts +16 -0
- package/src/chains/evm/index.ts +31 -0
- package/src/chains/evm/prompts.ts +193 -0
- package/src/chains/evm/providers/get-balance.ts +123 -0
- package/src/chains/evm/providers/wallet.ts +715 -0
- package/src/chains/evm/routes/sign.ts +333 -0
- package/src/chains/evm/rpc-providers.ts +410 -0
- package/src/chains/evm/service.ts +140 -0
- package/src/chains/evm/templates/index.ts +10 -0
- package/src/chains/evm/types/index.ts +432 -0
- package/src/chains/evm/vitest.config.ts +18 -0
- package/src/chains/registry.ts +668 -0
- package/src/chains/solana/README.md +367 -0
- package/src/chains/wallet-action.ts +533 -0
- package/src/chains/wallet-router.test.ts +296 -0
- package/src/contracts.ts +65 -0
- package/src/core-augmentation.ts +10 -0
- package/src/index.ts +71 -0
- package/src/lib/server-wallet-trade.ts +192 -0
- package/src/lib/wallet-export-guard.ts +330 -0
- package/src/lp/actions/liquidity.ts +827 -0
- package/src/lp/e2e/real-token-tests.ts +428 -0
- package/src/lp/e2e/scenarios.ts +470 -0
- package/src/lp/e2e/test-utils.ts +145 -0
- package/src/lp/lp-manager-entry.ts +303 -0
- package/src/lp/services/ConcentratedLiquidityService.ts +120 -0
- package/src/lp/services/DexInteractionService.ts +226 -0
- package/src/lp/services/LpManagementService.test.ts +148 -0
- package/src/lp/services/LpManagementService.ts +632 -0
- package/src/lp/services/UserLpProfileService.ts +163 -0
- package/src/lp/services/VaultService.ts +153 -0
- package/src/lp/services/YieldOptimizationService.ts +344 -0
- package/src/lp/services/__tests__/MockLpService.ts +146 -0
- package/src/lp/tasks/LpAutoRebalanceTask.ts +117 -0
- package/src/lp/tasks/__tests__/LpAutoRebalanceTask.test.ts +370 -0
- package/src/lp/types.ts +582 -0
- package/src/lp/utils/solanaClient.ts +143 -0
- package/src/plugin.ts +125 -0
- package/src/policy/policy.ts +19 -0
- package/src/providers/canonical-provider.ts +27 -0
- package/src/providers/unified-wallet-provider.ts +79 -0
- package/src/register-routes.ts +11 -0
- package/src/routes/plugin.ts +47 -0
- package/src/routes/wallet-market-overview-route.ts +869 -0
- package/src/sdk/abi.ts +258 -0
- package/src/sdk/bridge/abis.ts +126 -0
- package/src/sdk/bridge/client.ts +518 -0
- package/src/sdk/bridge/index.ts +56 -0
- package/src/sdk/bridge/solana.ts +604 -0
- package/src/sdk/bridge/types.ts +202 -0
- package/src/sdk/convenience.ts +347 -0
- package/src/sdk/escrow/MutualStakeEscrow.ts +480 -0
- package/src/sdk/escrow/types.ts +64 -0
- package/src/sdk/escrow/verifiers.ts +73 -0
- package/src/sdk/identity/erc8004.ts +692 -0
- package/src/sdk/identity/reputation.ts +449 -0
- package/src/sdk/identity/uaid.ts +497 -0
- package/src/sdk/identity/validation.ts +372 -0
- package/src/sdk/index.ts +763 -0
- package/src/sdk/policy/SpendingPolicy.ts +260 -0
- package/src/sdk/policy/UptoBillingPolicy.ts +320 -0
- package/src/sdk/router/PaymentRouter.ts +215 -0
- package/src/sdk/router/index.ts +8 -0
- package/src/sdk/swap/SwapModule.ts +310 -0
- package/src/sdk/swap/abi.ts +117 -0
- package/src/sdk/swap/index.ts +34 -0
- package/src/sdk/swap/types.ts +135 -0
- package/src/sdk/tokens/decimals.ts +140 -0
- package/src/sdk/tokens/registry.ts +911 -0
- package/src/sdk/tokens/solana.ts +419 -0
- package/src/sdk/tokens/transfers.ts +327 -0
- package/src/sdk/types.ts +158 -0
- package/src/sdk/wallet-core.ts +115 -0
- package/src/sdk/x402/budget.ts +168 -0
- package/src/sdk/x402/chains/abstract/index.ts +280 -0
- package/src/sdk/x402/client.ts +320 -0
- package/src/sdk/x402/index.ts +46 -0
- package/src/sdk/x402/middleware.ts +92 -0
- package/src/sdk/x402/multi-asset.ts +144 -0
- package/src/sdk/x402/types.ts +156 -0
- package/src/services/wallet-backend-service.ts +328 -0
- package/src/types/wallet-router.ts +227 -0
- package/src/utils/intent-trajectory.ts +106 -0
- package/src/wallet/backend.ts +62 -0
- package/src/wallet/errors.ts +49 -0
- package/src/wallet/index.ts +27 -0
- package/src/wallet/local-eoa-backend.ts +201 -0
- package/src/wallet/pending.ts +60 -0
- package/src/wallet/select-backend.ts +47 -0
- package/src/wallet/steward-backend.ts +161 -0
- package/src/wallet-action.ts +1 -0
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
// @ts-nocheck — legacy code from absorbed plugins (lp-manager, lpinfo, dexscreener, defi-news, birdeye); strict types pending cleanup
|
|
2
|
+
import type { IAgentRuntime } from "@elizaos/core";
|
|
3
|
+
import { Service } from "@elizaos/core";
|
|
4
|
+
import type { RealWorldNewsArticle } from "../interfaces/types";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* RSS Feed Item Interface
|
|
8
|
+
*/
|
|
9
|
+
interface RSSItem {
|
|
10
|
+
title?: string;
|
|
11
|
+
link?: string;
|
|
12
|
+
description?: string;
|
|
13
|
+
pubDate?: string;
|
|
14
|
+
category?: string[];
|
|
15
|
+
guid?: string;
|
|
16
|
+
content?: string;
|
|
17
|
+
creator?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Brave New Coin RSS Service for Real-World Crypto Events
|
|
22
|
+
*
|
|
23
|
+
* This service fetches real-world news and events related to cryptocurrency
|
|
24
|
+
* from Brave New Coin RSS feed.
|
|
25
|
+
*/
|
|
26
|
+
export class NewsDataService extends Service {
|
|
27
|
+
static serviceType = "NEWS_DATA_SERVICE";
|
|
28
|
+
private rssUrl: string = "https://bravenewcoin.com/rss/insights";
|
|
29
|
+
|
|
30
|
+
get capabilityDescription(): string {
|
|
31
|
+
return "Provides real-world cryptocurrency news and events from Brave New Coin RSS feed";
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
constructor(runtime?: IAgentRuntime) {
|
|
35
|
+
super(runtime);
|
|
36
|
+
console.log(
|
|
37
|
+
"✅ [NewsDataService] Initialized with Brave New Coin RSS feed",
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Start the NewsData service (static method for framework)
|
|
43
|
+
*/
|
|
44
|
+
static async start(runtime: IAgentRuntime) {
|
|
45
|
+
const service = new NewsDataService(runtime);
|
|
46
|
+
return service;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Stop the NewsData service (static method for framework)
|
|
51
|
+
*/
|
|
52
|
+
static async stop(runtime: IAgentRuntime) {
|
|
53
|
+
const service = runtime.getService(NewsDataService.serviceType);
|
|
54
|
+
if (!service) {
|
|
55
|
+
throw new Error(`${NewsDataService.serviceType} service not found`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Stop the service instance
|
|
61
|
+
*/
|
|
62
|
+
async stop(): Promise<void> {
|
|
63
|
+
console.log("✅ [NewsDataService] Stopped");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Parse RSS XML to extract news items
|
|
68
|
+
*/
|
|
69
|
+
private parseRSS(xmlText: string): RSSItem[] {
|
|
70
|
+
const items: RSSItem[] = [];
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
// Extract all <item> blocks from the RSS feed
|
|
74
|
+
const itemRegex = /<item>([\s\S]*?)<\/item>/g;
|
|
75
|
+
const itemMatches = xmlText.matchAll(itemRegex);
|
|
76
|
+
|
|
77
|
+
for (const match of itemMatches) {
|
|
78
|
+
const itemXml = match[1];
|
|
79
|
+
|
|
80
|
+
// Extract individual fields
|
|
81
|
+
const title = this.decodeHtmlEntities(
|
|
82
|
+
this.extractTag(itemXml, "title") || "",
|
|
83
|
+
);
|
|
84
|
+
const link = this.extractTag(itemXml, "link");
|
|
85
|
+
const description = this.extractTag(itemXml, "description");
|
|
86
|
+
const pubDate = this.extractTag(itemXml, "pubDate");
|
|
87
|
+
const guid = this.extractTag(itemXml, "guid");
|
|
88
|
+
const creator =
|
|
89
|
+
this.extractTag(itemXml, "dc:creator") ||
|
|
90
|
+
this.extractTag(itemXml, "author");
|
|
91
|
+
const content = this.extractTag(itemXml, "content:encoded");
|
|
92
|
+
|
|
93
|
+
// Extract categories (handle CDATA)
|
|
94
|
+
const categoryRegex =
|
|
95
|
+
/<category>(?:<!\[CDATA\[)?(.*?)(?:\]\]>)?<\/category>/gs;
|
|
96
|
+
const categories: string[] = [];
|
|
97
|
+
for (;;) {
|
|
98
|
+
const categoryMatch = categoryRegex.exec(itemXml);
|
|
99
|
+
if (categoryMatch === null) break;
|
|
100
|
+
const cat = categoryMatch[1].trim();
|
|
101
|
+
if (cat) {
|
|
102
|
+
categories.push(cat);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
items.push({
|
|
107
|
+
title,
|
|
108
|
+
link,
|
|
109
|
+
description,
|
|
110
|
+
pubDate,
|
|
111
|
+
category: categories.length > 0 ? categories : undefined,
|
|
112
|
+
guid,
|
|
113
|
+
creator,
|
|
114
|
+
content,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
} catch (error) {
|
|
118
|
+
console.error("❌ [NewsDataService] Error parsing RSS:", error);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return items;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Extract content from XML tag
|
|
126
|
+
*/
|
|
127
|
+
private extractTag(xml: string, tagName: string): string | undefined {
|
|
128
|
+
const regex = new RegExp(
|
|
129
|
+
`<${tagName}[^>]*><!\\[CDATA\\[(.*?)\\]\\]><\\/${tagName}>`,
|
|
130
|
+
"s",
|
|
131
|
+
);
|
|
132
|
+
const cdataMatch = xml.match(regex);
|
|
133
|
+
if (cdataMatch) {
|
|
134
|
+
return cdataMatch[1].trim();
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const simpleRegex = new RegExp(
|
|
138
|
+
`<${tagName}[^>]*>(.*?)<\\/${tagName}>`,
|
|
139
|
+
"s",
|
|
140
|
+
);
|
|
141
|
+
const simpleMatch = xml.match(simpleRegex);
|
|
142
|
+
if (simpleMatch) {
|
|
143
|
+
return simpleMatch[1].trim();
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return undefined;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Strip HTML tags from text
|
|
151
|
+
*/
|
|
152
|
+
private stripHtml(html: string): string {
|
|
153
|
+
return html.replace(/<[^>]*>/g, "").trim();
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Decode HTML entities (e.g., ’ to ')
|
|
158
|
+
*/
|
|
159
|
+
private decodeHtmlEntities(text: string): string {
|
|
160
|
+
const entities: Record<string, string> = {
|
|
161
|
+
"’": "'",
|
|
162
|
+
"‘": "'",
|
|
163
|
+
"“": '"',
|
|
164
|
+
"”": '"',
|
|
165
|
+
"–": "–",
|
|
166
|
+
"—": "—",
|
|
167
|
+
"&": "&",
|
|
168
|
+
"&": "&",
|
|
169
|
+
"<": "<",
|
|
170
|
+
">": ">",
|
|
171
|
+
""": '"',
|
|
172
|
+
"'": "'",
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
let decoded = text;
|
|
176
|
+
for (const [entity, char] of Object.entries(entities)) {
|
|
177
|
+
decoded = decoded.replace(new RegExp(entity, "g"), char);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Handle numeric entities
|
|
181
|
+
decoded = decoded.replace(/&#(\d+);/g, (_match, dec) => {
|
|
182
|
+
return String.fromCharCode(dec);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
return decoded;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Fetch latest crypto news from Brave New Coin RSS feed
|
|
190
|
+
*/
|
|
191
|
+
async getLatestNews(options?: {
|
|
192
|
+
query?: string;
|
|
193
|
+
language?: string;
|
|
194
|
+
category?: string;
|
|
195
|
+
limit?: number;
|
|
196
|
+
}): Promise<RealWorldNewsArticle[]> {
|
|
197
|
+
try {
|
|
198
|
+
const limit = options?.limit || 10;
|
|
199
|
+
const query = options?.query?.toLowerCase();
|
|
200
|
+
|
|
201
|
+
console.log(
|
|
202
|
+
`🔍 [NewsDataService] Fetching news from Brave New Coin RSS feed`,
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
const response = await fetch(this.rssUrl, {
|
|
206
|
+
method: "GET",
|
|
207
|
+
headers: {
|
|
208
|
+
"User-Agent": "Mozilla/5.0 (compatible; SpartanBot/1.0)",
|
|
209
|
+
},
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
if (!response.ok) {
|
|
213
|
+
const errorText = await response.text();
|
|
214
|
+
console.error(
|
|
215
|
+
`❌ [NewsDataService] RSS fetch error (${response.status}): ${errorText}`,
|
|
216
|
+
);
|
|
217
|
+
throw new Error(
|
|
218
|
+
`RSS fetch error: ${response.status} ${response.statusText}`,
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const xmlText = await response.text();
|
|
223
|
+
const rssItems = this.parseRSS(xmlText);
|
|
224
|
+
|
|
225
|
+
console.log(
|
|
226
|
+
`✅ [NewsDataService] Parsed ${rssItems.length} news articles from RSS`,
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
// Convert RSS items to RealWorldNewsArticle format
|
|
230
|
+
let articles: RealWorldNewsArticle[] = rssItems.map((item, index) => ({
|
|
231
|
+
article_id: item.guid || `bnc-${Date.now()}-${index}`,
|
|
232
|
+
title: item.title || "Untitled",
|
|
233
|
+
link: item.link || "",
|
|
234
|
+
description: item.description
|
|
235
|
+
? this.decodeHtmlEntities(this.stripHtml(item.description))
|
|
236
|
+
: undefined,
|
|
237
|
+
pubDate: item.pubDate || new Date().toISOString(),
|
|
238
|
+
source_id: "bravenewcoin",
|
|
239
|
+
source_priority: 1,
|
|
240
|
+
source_url: "https://bravenewcoin.com",
|
|
241
|
+
language: "en",
|
|
242
|
+
category: item.category,
|
|
243
|
+
creator: item.creator ? [item.creator] : undefined,
|
|
244
|
+
keywords: undefined,
|
|
245
|
+
video_url: null,
|
|
246
|
+
content: item.content ? this.stripHtml(item.content) : undefined,
|
|
247
|
+
image_url: undefined,
|
|
248
|
+
source_icon: undefined,
|
|
249
|
+
country: undefined,
|
|
250
|
+
ai_tag: undefined,
|
|
251
|
+
sentiment: undefined,
|
|
252
|
+
sentiment_stats: undefined,
|
|
253
|
+
ai_region: undefined,
|
|
254
|
+
}));
|
|
255
|
+
|
|
256
|
+
// Filter by query if provided
|
|
257
|
+
if (query) {
|
|
258
|
+
articles = articles.filter((article) => {
|
|
259
|
+
const searchText =
|
|
260
|
+
`${article.title} ${article.description || ""} ${article.content || ""} ${article.category?.join(" ") || ""}`.toLowerCase();
|
|
261
|
+
return searchText.includes(query);
|
|
262
|
+
});
|
|
263
|
+
console.log(
|
|
264
|
+
`🔍 [NewsDataService] Filtered to ${articles.length} articles matching query: ${query}`,
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Limit results
|
|
269
|
+
articles = articles.slice(0, limit);
|
|
270
|
+
|
|
271
|
+
return articles;
|
|
272
|
+
} catch (error) {
|
|
273
|
+
if (error instanceof Error) {
|
|
274
|
+
console.error(
|
|
275
|
+
"❌ [NewsDataService] Error fetching news:",
|
|
276
|
+
error.message,
|
|
277
|
+
);
|
|
278
|
+
throw error;
|
|
279
|
+
} else {
|
|
280
|
+
console.error("❌ [NewsDataService] Unknown error:", error);
|
|
281
|
+
throw new Error("Failed to fetch news from Brave New Coin RSS");
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Fetch news about a specific token
|
|
288
|
+
*/
|
|
289
|
+
async getTokenNews(
|
|
290
|
+
tokenSymbol: string,
|
|
291
|
+
options?: {
|
|
292
|
+
language?: string;
|
|
293
|
+
limit?: number;
|
|
294
|
+
},
|
|
295
|
+
): Promise<RealWorldNewsArticle[]> {
|
|
296
|
+
const query = tokenSymbol.toLowerCase();
|
|
297
|
+
return this.getLatestNews({
|
|
298
|
+
query,
|
|
299
|
+
language: options?.language,
|
|
300
|
+
limit: options?.limit,
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Fetch DeFi-specific news
|
|
306
|
+
*/
|
|
307
|
+
async getDefiNews(options?: {
|
|
308
|
+
language?: string;
|
|
309
|
+
limit?: number;
|
|
310
|
+
}): Promise<RealWorldNewsArticle[]> {
|
|
311
|
+
const query = "defi";
|
|
312
|
+
return this.getLatestNews({
|
|
313
|
+
query,
|
|
314
|
+
language: options?.language,
|
|
315
|
+
limit: options?.limit,
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Fetch blockchain and crypto market news
|
|
321
|
+
*/
|
|
322
|
+
async getCryptoMarketNews(options?: {
|
|
323
|
+
language?: string;
|
|
324
|
+
limit?: number;
|
|
325
|
+
}): Promise<RealWorldNewsArticle[]> {
|
|
326
|
+
// Return all crypto news from the feed
|
|
327
|
+
return this.getLatestNews({
|
|
328
|
+
language: options?.language,
|
|
329
|
+
limit: options?.limit,
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
// @ts-nocheck — legacy code from absorbed plugins (lp-manager, lpinfo, dexscreener, defi-news, birdeye); strict types pending cleanup
|
|
2
|
+
/**
|
|
3
|
+
* Utility functions for formatting DeFi news data
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Format a number as currency (USD)
|
|
8
|
+
*/
|
|
9
|
+
export function formatCurrency(value: number, decimals: number = 2): string {
|
|
10
|
+
if (value >= 1e12) {
|
|
11
|
+
return `$${(value / 1e12).toFixed(decimals)}T`;
|
|
12
|
+
} else if (value >= 1e9) {
|
|
13
|
+
return `$${(value / 1e9).toFixed(decimals)}B`;
|
|
14
|
+
} else if (value >= 1e6) {
|
|
15
|
+
return `$${(value / 1e6).toFixed(decimals)}M`;
|
|
16
|
+
} else if (value >= 1e3) {
|
|
17
|
+
return `$${(value / 1e3).toFixed(decimals)}K`;
|
|
18
|
+
} else {
|
|
19
|
+
return `$${value.toFixed(decimals)}`;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Format a percentage with appropriate emoji
|
|
25
|
+
*/
|
|
26
|
+
export function formatPercentage(value: number, decimals: number = 2): string {
|
|
27
|
+
const emoji = value >= 0 ? "📈" : "📉";
|
|
28
|
+
const sign = value >= 0 ? "+" : "";
|
|
29
|
+
return `${emoji} ${sign}${value.toFixed(decimals)}%`;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Format a timestamp as a human-readable date
|
|
34
|
+
*/
|
|
35
|
+
export function formatDate(timestamp: number | string): string {
|
|
36
|
+
const date = new Date(timestamp);
|
|
37
|
+
return date.toLocaleString();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Format a relative time (e.g., "2 hours ago")
|
|
42
|
+
*/
|
|
43
|
+
export function formatRelativeTime(timestamp: number | string): string {
|
|
44
|
+
const now = Date.now();
|
|
45
|
+
const date = new Date(timestamp).getTime();
|
|
46
|
+
const diff = now - date;
|
|
47
|
+
|
|
48
|
+
const seconds = Math.floor(diff / 1000);
|
|
49
|
+
const minutes = Math.floor(seconds / 60);
|
|
50
|
+
const hours = Math.floor(minutes / 60);
|
|
51
|
+
const days = Math.floor(hours / 24);
|
|
52
|
+
|
|
53
|
+
if (days > 0) {
|
|
54
|
+
return `${days} day${days > 1 ? "s" : ""} ago`;
|
|
55
|
+
} else if (hours > 0) {
|
|
56
|
+
return `${hours} hour${hours > 1 ? "s" : ""} ago`;
|
|
57
|
+
} else if (minutes > 0) {
|
|
58
|
+
return `${minutes} minute${minutes > 1 ? "s" : ""} ago`;
|
|
59
|
+
} else {
|
|
60
|
+
return `${seconds} second${seconds > 1 ? "s" : ""} ago`;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Truncate text to a maximum length
|
|
66
|
+
*/
|
|
67
|
+
export function truncateText(text: string, maxLength: number = 200): string {
|
|
68
|
+
if (text.length <= maxLength) {
|
|
69
|
+
return text;
|
|
70
|
+
}
|
|
71
|
+
return `${text.substring(0, maxLength)}...`;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Get sentiment emoji
|
|
76
|
+
*/
|
|
77
|
+
export function getSentimentEmoji(sentiment?: string): string {
|
|
78
|
+
if (!sentiment) return "😐";
|
|
79
|
+
|
|
80
|
+
switch (sentiment.toLowerCase()) {
|
|
81
|
+
case "positive":
|
|
82
|
+
return "😊";
|
|
83
|
+
case "negative":
|
|
84
|
+
return "😟";
|
|
85
|
+
case "neutral":
|
|
86
|
+
return "😐";
|
|
87
|
+
default:
|
|
88
|
+
return "😐";
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Format large numbers with commas
|
|
94
|
+
*/
|
|
95
|
+
export function formatNumber(value: number, decimals: number = 0): string {
|
|
96
|
+
return value.toLocaleString("en-US", {
|
|
97
|
+
minimumFractionDigits: decimals,
|
|
98
|
+
maximumFractionDigits: decimals,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Extract token symbol from text
|
|
104
|
+
*/
|
|
105
|
+
export function extractTokenSymbol(text: string): string | null {
|
|
106
|
+
// Match 3-5 uppercase letters that might be a token symbol
|
|
107
|
+
const match = text.match(/\b([A-Z]{3,5})\b/);
|
|
108
|
+
return match ? match[1] : null;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Format OHLCV data for display
|
|
113
|
+
*/
|
|
114
|
+
export function formatOHLCV(candle: {
|
|
115
|
+
timestamp: number;
|
|
116
|
+
open: number;
|
|
117
|
+
high: number;
|
|
118
|
+
low: number;
|
|
119
|
+
close: number;
|
|
120
|
+
volume?: number;
|
|
121
|
+
}): string {
|
|
122
|
+
const date = formatDate(candle.timestamp);
|
|
123
|
+
let result = `📅 ${date}\n`;
|
|
124
|
+
result += ` Open: ${formatCurrency(candle.open)}\n`;
|
|
125
|
+
result += ` High: ${formatCurrency(candle.high)}\n`;
|
|
126
|
+
result += ` Low: ${formatCurrency(candle.low)}\n`;
|
|
127
|
+
result += ` Close: ${formatCurrency(candle.close)}`;
|
|
128
|
+
if (candle.volume !== undefined) {
|
|
129
|
+
result += `\n Volume: ${formatCurrency(candle.volume)}`;
|
|
130
|
+
}
|
|
131
|
+
return result;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Clean HTML tags from text
|
|
136
|
+
*/
|
|
137
|
+
export function stripHtml(html: string): string {
|
|
138
|
+
return html.replace(/<[^>]*>/g, "");
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Validate if a string is a valid token address
|
|
143
|
+
*/
|
|
144
|
+
export function isValidTokenAddress(address: string): boolean {
|
|
145
|
+
// Ethereum address (0x followed by 40 hex characters)
|
|
146
|
+
const ethRegex = /^0x[a-fA-F0-9]{40}$/;
|
|
147
|
+
// Solana address (base58, 32-44 characters)
|
|
148
|
+
const solRegex = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
|
|
149
|
+
|
|
150
|
+
return ethRegex.test(address) || solRegex.test(address);
|
|
151
|
+
}
|