diff --git a/agent/package.json b/agent/package.json index 8fe3f226b5..1f49a34fbf 100644 --- a/agent/package.json +++ b/agent/package.json @@ -34,6 +34,7 @@ "@elizaos/plugin-0g": "workspace:*", "@elizaos/plugin-abstract": "workspace:*", "@elizaos/plugin-aptos": "workspace:*", + "@elizaos/plugin-coinmarketcap": "workspace:*", "@elizaos/plugin-binance": "workspace:*", "@elizaos/plugin-avail": "workspace:*", "@elizaos/plugin-bootstrap": "workspace:*", diff --git a/agent/src/index.ts b/agent/src/index.ts index ed337cceee..2d851d85ae 100644 --- a/agent/src/index.ts +++ b/agent/src/index.ts @@ -1,7 +1,7 @@ +import { PGLiteDatabaseAdapter } from "@elizaos/adapter-pglite"; import { PostgresDatabaseAdapter } from "@elizaos/adapter-postgres"; import { RedisClient } from "@elizaos/adapter-redis"; import { SqliteDatabaseAdapter } from "@elizaos/adapter-sqlite"; -import { PGLiteDatabaseAdapter } from "@elizaos/adapter-pglite"; import { AutoClientInterface } from "@elizaos/client-auto"; import { DiscordClientInterface } from "@elizaos/client-discord"; import { FarcasterAgentClient } from "@elizaos/client-farcaster"; @@ -31,14 +31,17 @@ import { validateCharacterConfig, } from "@elizaos/core"; import { zgPlugin } from "@elizaos/plugin-0g"; + import { bootstrapPlugin } from "@elizaos/plugin-bootstrap"; import createGoatPlugin from "@elizaos/plugin-goat"; // import { intifacePlugin } from "@elizaos/plugin-intiface"; import { DirectClient } from "@elizaos/client-direct"; import { ThreeDGenerationPlugin } from "@elizaos/plugin-3d-generation"; import { abstractPlugin } from "@elizaos/plugin-abstract"; -import { aptosPlugin } from "@elizaos/plugin-aptos"; import { alloraPlugin } from "@elizaos/plugin-allora"; +import { aptosPlugin } from "@elizaos/plugin-aptos"; +import { artheraPlugin } from "@elizaos/plugin-arthera"; +import { availPlugin } from "@elizaos/plugin-avail"; import { avalanchePlugin } from "@elizaos/plugin-avalanche"; import { binancePlugin } from "@elizaos/plugin-binance"; import { @@ -49,12 +52,13 @@ import { tradePlugin, webhookPlugin, } from "@elizaos/plugin-coinbase"; +import { coinmarketcapPlugin } from "@elizaos/plugin-coinmarketcap"; import { coinPricePlugin } from "@elizaos/plugin-coinprice"; import { confluxPlugin } from "@elizaos/plugin-conflux"; +import { createCosmosPlugin } from "@elizaos/plugin-cosmos"; import { cronosZkEVMPlugin } from "@elizaos/plugin-cronoszkevm"; import { echoChambersPlugin } from "@elizaos/plugin-echochambers"; import { evmPlugin } from "@elizaos/plugin-evm"; -import { createCosmosPlugin } from "@elizaos/plugin-cosmos"; import { flowPlugin } from "@elizaos/plugin-flow"; import { fuelPlugin } from "@elizaos/plugin-fuel"; import { genLayerPlugin } from "@elizaos/plugin-genlayer"; @@ -63,24 +67,25 @@ import { multiversxPlugin } from "@elizaos/plugin-multiversx"; import { nearPlugin } from "@elizaos/plugin-near"; import { nftGenerationPlugin } from "@elizaos/plugin-nft-generation"; import { createNodePlugin } from "@elizaos/plugin-node"; +import { obsidianPlugin } from "@elizaos/plugin-obsidian"; +import { openWeatherPlugin } from "@elizaos/plugin-open-weather"; import { solanaPlugin } from "@elizaos/plugin-solana"; import { solanaAgentkitPlguin } from "@elizaos/plugin-solana-agentkit"; +import { stargazePlugin } from "@elizaos/plugin-stargaze"; import { storyPlugin } from "@elizaos/plugin-story"; import { suiPlugin } from "@elizaos/plugin-sui"; import { TEEMode, teePlugin } from "@elizaos/plugin-tee"; import { teeMarlinPlugin } from "@elizaos/plugin-tee-marlin"; +import { thirdwebPlugin } from "@elizaos/plugin-thirdweb"; import { tonPlugin } from "@elizaos/plugin-ton"; import { webSearchPlugin } from "@elizaos/plugin-web-search"; + import { giphyPlugin } from "@elizaos/plugin-giphy"; import { echoChamberPlugin } from "@elizaos/plugin-echochambers"; import { letzAIPlugin } from "@elizaos/plugin-letzai"; import { thirdwebPlugin } from "@elizaos/plugin-thirdweb"; + import { zksyncEraPlugin } from "@elizaos/plugin-zksync-era"; -import { availPlugin } from "@elizaos/plugin-avail"; -import { openWeatherPlugin } from "@elizaos/plugin-open-weather"; -import { artheraPlugin } from "@elizaos/plugin-arthera"; -import { stargazePlugin } from "@elizaos/plugin-stargaze"; -import { obsidianPlugin } from "@elizaos/plugin-obsidian"; import Database from "better-sqlite3"; import fs from "fs"; import net from "net"; @@ -631,6 +636,9 @@ export async function createAgent( ? nftGenerationPlugin : null, getSecret(character, "ZEROG_PRIVATE_KEY") ? zgPlugin : null, + getSecret(character, "COINMARKETCAP_API_KEY") + ? coinmarketcapPlugin + : null, getSecret(character, "COINBASE_COMMERCE_KEY") ? coinbaseCommercePlugin : null, diff --git a/packages/plugin-coinmarketcap/README.md b/packages/plugin-coinmarketcap/README.md new file mode 100644 index 0000000000..08e6294882 --- /dev/null +++ b/packages/plugin-coinmarketcap/README.md @@ -0,0 +1,127 @@ +# @elizaos/plugin-coinmarketcap + +A plugin for Eliza that enables cryptocurrency price checking using the CoinMarketCap API. + +## Features + +- Real-time cryptocurrency price checking +- Support for multiple cryptocurrencies (BTC, ETH, SOL, etc.) +- Currency conversion (USD, EUR, etc.) +- Detailed price and market data +- Natural language processing for price queries + +## Installation + +```bash +npm install @elizaos/plugin-coinmarketcap +``` + +## Configuration + +1. Get your API key from [CoinMarketCap](https://pro.coinmarketcap.com) + +2. Set up your environment variables: + +```bash +COINMARKETCAP_API_KEY=your_api_key +``` + +3. Register the plugin in your Eliza configuration: + +```typescript +import { CoinMarketCapPlugin } from "@elizaos/plugin-coinmarketcap"; + +// In your Eliza configuration +plugins: [ + new CoinMarketCapPlugin(), + // ... other plugins +]; +``` + +## Usage + +The plugin responds to natural language queries about cryptocurrency prices. Here are some examples: + +```plaintext +"What's the current price of Bitcoin?" +"Show me ETH price in USD" +"Get the price of SOL" +``` + +### Supported Cryptocurrencies + +The plugin supports major cryptocurrencies including: + +- Bitcoin (BTC) +- Ethereum (ETH) +- Solana (SOL) +- USD Coin (USDC) +- And many more... + +### Available Actions + +#### GET_PRICE + +Fetches the current price of a cryptocurrency. + +```typescript +// Example response format +{ + symbol: "BTC", + price: 50000.00, + currency: "USD", + marketCap: 1000000000000, + volume24h: 50000000000, + percentChange24h: 2.5 +} +``` + +## API Reference + +### Environment Variables + +| Variable | Description | Required | +| --------------------- | -------------------------- | -------- | +| COINMARKETCAP_API_KEY | Your CoinMarketCap API key | Yes | + +### Types + +```typescript +interface PriceData { + price: number; + marketCap: number; + volume24h: number; + percentChange24h: number; +} + +interface GetPriceContent { + symbol: string; + currency: string; +} +``` + +## Error Handling + +The plugin includes comprehensive error handling for: + +- Invalid API keys +- Rate limiting +- Network timeouts +- Invalid cryptocurrency symbols +- Unsupported currencies + +## Rate Limits + +CoinMarketCap API has different rate limits based on your subscription plan. Please refer to [CoinMarketCap's pricing page](https://coinmarketcap.com/api/pricing/) for detailed information. + +## Support + +For support, please open an issue in the repository or reach out to the maintainers: + +- Discord: 0xspit + +## Links + +- [CoinMarketCap API Documentation](https://coinmarketcap.com/api/documentation/v1/) + +- [GitHub Repository](https://github.com/elizaOS/eliza/tree/main/packages/plugin-coinmarketcap) diff --git a/packages/plugin-coinmarketcap/package.json b/packages/plugin-coinmarketcap/package.json new file mode 100644 index 0000000000..6dbdf24f1f --- /dev/null +++ b/packages/plugin-coinmarketcap/package.json @@ -0,0 +1,19 @@ +{ + "name": "@elizaos/plugin-coinmarketcap", + "version": "0.1.7-alpha.2", + "main": "dist/index.js", + "type": "module", + "types": "dist/index.d.ts", + "dependencies": { + "@elizaos/core": "workspace:*", + "axios": "^1.6.7", + "zod": "^3.22.4" + }, + "devDependencies": { + "tsup": "^8.3.5" + }, + "scripts": { + "build": "tsup --format esm --dts", + "dev": "tsup --format esm --dts --watch" + } +} \ No newline at end of file diff --git a/packages/plugin-coinmarketcap/src/actions/getPrice/examples.ts b/packages/plugin-coinmarketcap/src/actions/getPrice/examples.ts new file mode 100644 index 0000000000..5a6713b566 --- /dev/null +++ b/packages/plugin-coinmarketcap/src/actions/getPrice/examples.ts @@ -0,0 +1,46 @@ +import { ActionExample } from "@elizaos/core"; + +export const priceExamples: ActionExample[][] = [ + [ + { + user: "{{user1}}", + content: { + text: "What's the current price of Bitcoin?", + }, + }, + { + user: "{{agent}}", + content: { + text: "Let me check the current Bitcoin price for you.", + action: "GET_PRICE", + }, + }, + { + user: "{{agent}}", + content: { + text: "The current price of BTC is 65,432.21 USD", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Check ETH price in EUR", + }, + }, + { + user: "{{agent}}", + content: { + text: "I'll check the current Ethereum price in EUR.", + action: "GET_PRICE", + }, + }, + { + user: "{{agent}}", + content: { + text: "The current price of ETH is 2,345.67 EUR", + }, + }, + ], +]; diff --git a/packages/plugin-coinmarketcap/src/actions/getPrice/index.ts b/packages/plugin-coinmarketcap/src/actions/getPrice/index.ts new file mode 100644 index 0000000000..61ca090c02 --- /dev/null +++ b/packages/plugin-coinmarketcap/src/actions/getPrice/index.ts @@ -0,0 +1,118 @@ +import { + composeContext, + elizaLogger, + generateObjectDeprecated, + HandlerCallback, + IAgentRuntime, + Memory, + ModelClass, + State, + type Action, +} from "@elizaos/core"; +import { validateCoinMarketCapConfig } from "../../environment"; +import { priceExamples } from "./examples"; +import { createPriceService } from "./service"; +import { getPriceTemplate } from "./template"; +import { GetPriceContent } from "./types"; +import { isGetPriceContent } from "./validation"; + +export default { + name: "GET_PRICE", + similes: [ + "CHECK_PRICE", + "PRICE_CHECK", + "GET_CRYPTO_PRICE", + "CHECK_CRYPTO_PRICE", + "GET_TOKEN_PRICE", + "CHECK_TOKEN_PRICE", + ], + validate: async (runtime: IAgentRuntime, message: Memory) => { + await validateCoinMarketCapConfig(runtime); + return true; + }, + description: "Get the current price of a cryptocurrency from CoinMarketCap", + handler: async ( + runtime: IAgentRuntime, + message: Memory, + state: State, + _options: { [key: string]: unknown }, + callback?: HandlerCallback + ): Promise => { + elizaLogger.log("Starting CoinMarketCap GET_PRICE handler..."); + + // Initialize or update state + if (!state) { + state = (await runtime.composeState(message)) as State; + } else { + state = await runtime.updateRecentMessageState(state); + } + + try { + // Compose and generate price check content + const priceContext = composeContext({ + state, + template: getPriceTemplate, + }); + + const content = (await generateObjectDeprecated({ + runtime, + context: priceContext, + modelClass: ModelClass.SMALL, + })) as unknown as GetPriceContent; + + // Validate content + if (!isGetPriceContent(content)) { + throw new Error("Invalid price check content"); + } + + // Get price from CoinMarketCap + const config = await validateCoinMarketCapConfig(runtime); + + const priceService = createPriceService( + config.COINMARKETCAP_API_KEY + ); + + try { + const priceData = await priceService.getPrice( + content.symbol, + content.currency + ); + elizaLogger.success( + `Price retrieved successfully! ${content.symbol}: ${priceData.price} ${content.currency.toUpperCase()}` + ); + + if (callback) { + callback({ + text: `The current price of ${content.symbol} is ${priceData.price} ${content.currency.toUpperCase()}`, + content: { + symbol: content.symbol, + currency: content.currency, + ...priceData, + }, + }); + } + + return true; + } catch (error) { + elizaLogger.error("Error in GET_PRICE handler:", error); + if (callback) { + callback({ + text: `Error fetching price: ${error.message}`, + content: { error: error.message }, + }); + } + return false; + } + } catch (error) { + elizaLogger.error("Error in GET_PRICE handler:", error); + if (callback) { + callback({ + text: `Error fetching price: ${error.message}`, + content: { error: error.message }, + }); + } + return false; + } + }, + examples: priceExamples, +} as Action; diff --git a/packages/plugin-coinmarketcap/src/actions/getPrice/service.ts b/packages/plugin-coinmarketcap/src/actions/getPrice/service.ts new file mode 100644 index 0000000000..2b2d917092 --- /dev/null +++ b/packages/plugin-coinmarketcap/src/actions/getPrice/service.ts @@ -0,0 +1,71 @@ +import axios from "axios"; +import { ApiResponse, PriceData } from "./types"; + +const BASE_URL = "https://pro-api.coinmarketcap.com/v1"; + +export const createPriceService = (apiKey: string) => { + const client = axios.create({ + baseURL: BASE_URL, + headers: { + "X-CMC_PRO_API_KEY": apiKey, + Accept: "application/json", + }, + }); + + const getPrice = async ( + symbol: string, + currency: string + ): Promise => { + const normalizedSymbol = symbol.toUpperCase().trim(); + const normalizedCurrency = currency.toUpperCase().trim(); + + try { + const response = await client.get( + "/cryptocurrency/quotes/latest", + { + params: { + symbol: normalizedSymbol, + convert: normalizedCurrency, + }, + } + ); + + console.log( + "API Response:", + JSON.stringify(response.data, null, 2) + ); + + const symbolData = response.data.data[normalizedSymbol]; + if (!symbolData) { + throw new Error( + `No data found for symbol: ${normalizedSymbol}` + ); + } + + const quoteData = symbolData.quote[normalizedCurrency]; + if (!quoteData) { + throw new Error( + `No quote data found for currency: ${normalizedCurrency}` + ); + } + + return { + price: quoteData.price, + marketCap: quoteData.market_cap, + volume24h: quoteData.volume_24h, + percentChange24h: quoteData.percent_change_24h, + }; + } catch (error) { + if (axios.isAxiosError(error)) { + const errorMessage = + error.response?.data?.status?.error_message || + error.message; + console.error("API Error:", errorMessage); + throw new Error(`API Error: ${errorMessage}`); + } + throw error; + } + }; + + return { getPrice }; +}; diff --git a/packages/plugin-coinmarketcap/src/actions/getPrice/template.ts b/packages/plugin-coinmarketcap/src/actions/getPrice/template.ts new file mode 100644 index 0000000000..46e439a235 --- /dev/null +++ b/packages/plugin-coinmarketcap/src/actions/getPrice/template.ts @@ -0,0 +1,27 @@ +export const getPriceTemplate = `Respond with a JSON object containing BOTH symbol and currency. Currency must default to "USD" if not specified. + +Here are the cryptocurrency symbol mappings: +- bitcoin/btc -> BTC +- ethereum/eth -> ETH +- solana/sol -> SOL +- cardano/ada -> ADA +- ripple/xrp -> XRP +- dogecoin/doge -> DOGE +- polkadot/dot -> DOT +- usdc -> USDC +- tether/usdt -> USDT + +IMPORTANT: Response must ALWAYS include both "symbol" and "currency" fields. + +Example response: +\`\`\`json +{ + "symbol": "BTC", + "currency": "USD" +} +\`\`\` + +{{recentMessages}} + +Extract the cryptocurrency from the most recent message. Always include currency (default "USD"). +Respond with a JSON markdown block containing both symbol and currency.`; diff --git a/packages/plugin-coinmarketcap/src/actions/getPrice/types.ts b/packages/plugin-coinmarketcap/src/actions/getPrice/types.ts new file mode 100644 index 0000000000..7b84dde342 --- /dev/null +++ b/packages/plugin-coinmarketcap/src/actions/getPrice/types.ts @@ -0,0 +1,28 @@ +import { Content } from "@elizaos/core"; + +export interface GetPriceContent extends Content { + symbol: string; + currency: string; +} + +export interface PriceData { + price: number; + marketCap: number; + volume24h: number; + percentChange24h: number; +} + +export interface ApiResponse { + data: { + [symbol: string]: { + quote: { + [currency: string]: { + price: number; + market_cap: number; + volume_24h: number; + percent_change_24h: number; + }; + }; + }; + }; +} diff --git a/packages/plugin-coinmarketcap/src/actions/getPrice/validation.ts b/packages/plugin-coinmarketcap/src/actions/getPrice/validation.ts new file mode 100644 index 0000000000..16bbf67d61 --- /dev/null +++ b/packages/plugin-coinmarketcap/src/actions/getPrice/validation.ts @@ -0,0 +1,16 @@ +import { z } from "zod"; +import { GetPriceContent } from "./types"; + +export const GetPriceSchema = z.object({ + symbol: z.string(), + currency: z.string().default("USD"), +}); + +export function isGetPriceContent( + content: GetPriceContent +): content is GetPriceContent { + return ( + typeof content.symbol === "string" && + typeof content.currency === "string" + ); +} diff --git a/packages/plugin-coinmarketcap/src/environment.ts b/packages/plugin-coinmarketcap/src/environment.ts new file mode 100644 index 0000000000..d21d13bfdf --- /dev/null +++ b/packages/plugin-coinmarketcap/src/environment.ts @@ -0,0 +1,32 @@ +import { IAgentRuntime } from "@elizaos/core"; +import { z } from "zod"; + +export const coinmarketcapEnvSchema = z.object({ + COINMARKETCAP_API_KEY: z + .string() + .min(1, "CoinMarketCap API key is required"), +}); + +export type CoinMarketCapConfig = z.infer; + +export async function validateCoinMarketCapConfig( + runtime: IAgentRuntime +): Promise { + try { + const config = { + COINMARKETCAP_API_KEY: runtime.getSetting("COINMARKETCAP_API_KEY"), + }; + + return coinmarketcapEnvSchema.parse(config); + } catch (error) { + if (error instanceof z.ZodError) { + const errorMessages = error.errors + .map((err) => `${err.path.join(".")}: ${err.message}`) + .join("\n"); + throw new Error( + `CoinMarketCap configuration validation failed:\n${errorMessages}` + ); + } + throw error; + } +} diff --git a/packages/plugin-coinmarketcap/src/index.ts b/packages/plugin-coinmarketcap/src/index.ts new file mode 100644 index 0000000000..5da30cf5ab --- /dev/null +++ b/packages/plugin-coinmarketcap/src/index.ts @@ -0,0 +1,12 @@ +import { Plugin } from "@elizaos/core"; +import getPrice from "./actions/getPrice"; + +export const coinmarketcapPlugin: Plugin = { + name: "coinmarketcap", + description: "CoinMarketCap Plugin for Eliza", + actions: [getPrice], + evaluators: [], + providers: [], +}; + +export default coinmarketcapPlugin; diff --git a/packages/plugin-coinmarketcap/src/types.ts b/packages/plugin-coinmarketcap/src/types.ts new file mode 100644 index 0000000000..7b84dde342 --- /dev/null +++ b/packages/plugin-coinmarketcap/src/types.ts @@ -0,0 +1,28 @@ +import { Content } from "@elizaos/core"; + +export interface GetPriceContent extends Content { + symbol: string; + currency: string; +} + +export interface PriceData { + price: number; + marketCap: number; + volume24h: number; + percentChange24h: number; +} + +export interface ApiResponse { + data: { + [symbol: string]: { + quote: { + [currency: string]: { + price: number; + market_cap: number; + volume_24h: number; + percent_change_24h: number; + }; + }; + }; + }; +} diff --git a/packages/plugin-coinmarketcap/tsconfig.json b/packages/plugin-coinmarketcap/tsconfig.json new file mode 100644 index 0000000000..73993deaaf --- /dev/null +++ b/packages/plugin-coinmarketcap/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../core/tsconfig.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src" + }, + "include": [ + "src/**/*.ts" + ] +} \ No newline at end of file diff --git a/packages/plugin-coinmarketcap/tsup.config.ts b/packages/plugin-coinmarketcap/tsup.config.ts new file mode 100644 index 0000000000..58ed52c499 --- /dev/null +++ b/packages/plugin-coinmarketcap/tsup.config.ts @@ -0,0 +1,19 @@ +import { defineConfig } from "tsup"; + +export default defineConfig({ + entry: ["src/index.ts"], + outDir: "dist", + sourcemap: true, + clean: true, + format: ["esm"], + external: [ + "dotenv", + "fs", + "path", + "@reflink/reflink", + "@node-llama-cpp", + "https", + "http", + "agentkeepalive", + ], +}); diff --git a/packages/plugin-defillama/README.md b/packages/plugin-defillama/README.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/plugin-defillama/package.json b/packages/plugin-defillama/package.json new file mode 100644 index 0000000000..8413f4b7e1 --- /dev/null +++ b/packages/plugin-defillama/package.json @@ -0,0 +1,29 @@ +{ + "name": "@elizaos/plugin-defillama", + "version": "0.1.0", + "type": "module", + "main": "dist/index.js", + "module": "dist/index.js", + "types": "dist/index.d.ts", + "exports": { + "./package.json": "./package.json", + ".": { + "import": { + "@elizaos/source": "./src/index.ts", + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + } + } + }, + "files": [ + "dist" + ], + "dependencies": { + "@elizaos/core": "workspace:*", + "axios": "^1.6.0", + "tsup": "^8.3.5" + }, + "scripts": { + "build": "tsup --format esm --dts" + } +} \ No newline at end of file diff --git a/packages/plugin-defillama/src/actions/get-price.action.ts b/packages/plugin-defillama/src/actions/get-price.action.ts new file mode 100644 index 0000000000..35fb1b2bc9 --- /dev/null +++ b/packages/plugin-defillama/src/actions/get-price.action.ts @@ -0,0 +1,18 @@ +import { createAction } from "@elizaos/core"; +import { z } from "zod"; +import { DefiLlamaProvider } from "../providers/defillama.provider"; + +export const GetPriceSchema = z.object({ + tokenId: z.string(), +}); + +export const getPriceAction = createAction({ + name: "get-price", + description: "Get current price for a token from DefiLlama", + schema: GetPriceSchema, + handler: async ({ tokenId }, { provider }) => { + const defiLlama = provider as DefiLlamaProvider; + const price = await defiLlama.getCurrentPrice(tokenId); + return { price }; + }, +}); \ No newline at end of file diff --git a/packages/plugin-defillama/src/environment.ts b/packages/plugin-defillama/src/environment.ts new file mode 100644 index 0000000000..0d7f41870c --- /dev/null +++ b/packages/plugin-defillama/src/environment.ts @@ -0,0 +1,8 @@ +import { z } from "zod"; + +export const DefiLlamaEnvironmentSchema = z.object({ + DEFILLAMA_API_URL: z.string().default("https://coins.llama.fi"), + DEFILLAMA_TIMEOUT: z.coerce.number().default(10000), +}); + +export type DefiLlamaEnvironment = z.infer; diff --git a/packages/plugin-defillama/src/index.ts b/packages/plugin-defillama/src/index.ts new file mode 100644 index 0000000000..60e2d2a526 --- /dev/null +++ b/packages/plugin-defillama/src/index.ts @@ -0,0 +1,14 @@ +import { createPlugin } from "@elizaos/core"; +import { getPriceAction } from "./actions/get-price.action"; +import { DefiLlamaEnvironmentSchema } from "./environment"; +import { DefiLlamaProvider } from "./providers/defillama.provider"; + +export const DefiLlamaPlugin = createPlugin({ + name: "defillama", + version: "0.1.0", + environment: DefiLlamaEnvironmentSchema, + provider: ({ environment }) => new DefiLlamaProvider(environment), + actions: [getPriceAction], +}); + +export * from "./environment"; diff --git a/packages/plugin-defillama/src/providers/defillama.provider.ts b/packages/plugin-defillama/src/providers/defillama.provider.ts new file mode 100644 index 0000000000..a5a62c1b8d --- /dev/null +++ b/packages/plugin-defillama/src/providers/defillama.provider.ts @@ -0,0 +1,24 @@ +import axios, { AxiosInstance } from "axios"; +import { DefiLlamaEnvironment } from "../environment"; + +export class DefiLlamaProvider { + private client: AxiosInstance; + + constructor(environment: DefiLlamaEnvironment) { + this.client = axios.create({ + baseURL: environment.DEFILLAMA_API_URL, + timeout: environment.DEFILLAMA_TIMEOUT, + }); + } + + async getCurrentPrice(tokenId: string): Promise { + const { data } = await this.client.get(`/prices/current/${tokenId}`); + const priceData = data.coins[tokenId]; + + if (!priceData) { + throw new Error(`No price data found for token: ${tokenId}`); + } + + return priceData.price; + } +} \ No newline at end of file diff --git a/packages/plugin-defillama/tsconfig.json b/packages/plugin-defillama/tsconfig.json new file mode 100644 index 0000000000..73993deaaf --- /dev/null +++ b/packages/plugin-defillama/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../core/tsconfig.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src" + }, + "include": [ + "src/**/*.ts" + ] +} \ No newline at end of file diff --git a/packages/plugin-defillama/tsup.config.ts b/packages/plugin-defillama/tsup.config.ts new file mode 100644 index 0000000000..98c2d8e4c7 --- /dev/null +++ b/packages/plugin-defillama/tsup.config.ts @@ -0,0 +1,17 @@ +import { defineConfig } from "tsup"; + +export default defineConfig({ + entry: ["src/index.ts"], + outDir: "dist", + sourcemap: true, + clean: true, + format: ["esm"], + external: [ + "dotenv", + "fs", + "path", + "https", + "http", + "agentkeepalive", + ], +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 37a4895325..382a8d5df4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -184,6 +184,9 @@ importers: '@elizaos/plugin-coinbase': specifier: workspace:* version: link:../packages/plugin-coinbase + '@elizaos/plugin-coinmarketcap': + specifier: workspace:* + version: link:../packages/plugin-coinmarketcap '@elizaos/plugin-coinprice': specifier: workspace:* version: link:../packages/plugin-coinprice @@ -1303,6 +1306,22 @@ importers: specifier: ^8.3.5 version: 8.3.5(@swc/core@1.10.6(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.7.0) + packages/plugin-coinmarketcap: + dependencies: + '@elizaos/core': + specifier: workspace:* + version: link:../core + axios: + specifier: ^1.6.7 + version: 1.7.9(debug@4.4.0) + zod: + specifier: ^3.22.4 + version: 3.23.8 + devDependencies: + tsup: + specifier: ^8.3.5 + version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + packages/plugin-conflux: dependencies: '@elizaos/core': @@ -47587,6 +47606,25 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.2 + viem@2.21.58(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8): + dependencies: + '@noble/curves': 1.7.0 + '@noble/hashes': 1.6.1 + '@scure/bip32': 1.6.0 + '@scure/bip39': 1.5.0 + abitype: 1.0.7(typescript@5.6.3)(zod@3.23.8) + isows: 1.0.6(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + ox: 0.4.4(typescript@5.6.3)(zod@3.23.8) + webauthn-p256: 0.0.10 + ws: 8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + optionalDependencies: + typescript: 5.6.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + - zod + + vite-node@2.1.4(@types/node@22.10.5)(terser@5.37.0): viem@2.21.58(bufferutil@4.0.9)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.24.1): dependencies: '@noble/curves': 1.7.0