From 30b4680ad1d3afff45876650b553878bc9e973c7 Mon Sep 17 00:00:00 2001 From: Sayo <82053242+wtfsayo@users.noreply.github.com> Date: Wed, 8 Jan 2025 21:38:49 +0530 Subject: [PATCH 1/3] remove defillama plugin --- packages/plugin-defillama/README.md | 0 packages/plugin-defillama/package.json | 29 ------------------- .../src/actions/get-price.action.ts | 18 ------------ packages/plugin-defillama/src/environment.ts | 8 ----- packages/plugin-defillama/src/index.ts | 14 --------- .../src/providers/defillama.provider.ts | 24 --------------- packages/plugin-defillama/tsconfig.json | 10 ------- packages/plugin-defillama/tsup.config.ts | 17 ----------- 8 files changed, 120 deletions(-) delete mode 100644 packages/plugin-defillama/README.md delete mode 100644 packages/plugin-defillama/package.json delete mode 100644 packages/plugin-defillama/src/actions/get-price.action.ts delete mode 100644 packages/plugin-defillama/src/environment.ts delete mode 100644 packages/plugin-defillama/src/index.ts delete mode 100644 packages/plugin-defillama/src/providers/defillama.provider.ts delete mode 100644 packages/plugin-defillama/tsconfig.json delete mode 100644 packages/plugin-defillama/tsup.config.ts diff --git a/packages/plugin-defillama/README.md b/packages/plugin-defillama/README.md deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/packages/plugin-defillama/package.json b/packages/plugin-defillama/package.json deleted file mode 100644 index 8413f4b7e15..00000000000 --- a/packages/plugin-defillama/package.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "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 deleted file mode 100644 index 35fb1b2bc91..00000000000 --- a/packages/plugin-defillama/src/actions/get-price.action.ts +++ /dev/null @@ -1,18 +0,0 @@ -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 deleted file mode 100644 index 0d7f41870cb..00000000000 --- a/packages/plugin-defillama/src/environment.ts +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index 60e2d2a526f..00000000000 --- a/packages/plugin-defillama/src/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -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 deleted file mode 100644 index a5a62c1b8d3..00000000000 --- a/packages/plugin-defillama/src/providers/defillama.provider.ts +++ /dev/null @@ -1,24 +0,0 @@ -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 deleted file mode 100644 index 73993deaaf7..00000000000 --- a/packages/plugin-defillama/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "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 deleted file mode 100644 index 98c2d8e4c70..00000000000 --- a/packages/plugin-defillama/tsup.config.ts +++ /dev/null @@ -1,17 +0,0 @@ -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", - ], -}); From f8ef4d7a7e7915f1290a8ca197f687472416505e Mon Sep 17 00:00:00 2001 From: Sayo <82053242+wtfsayo@users.noreply.github.com> Date: Wed, 8 Jan 2025 21:48:14 +0530 Subject: [PATCH 2/3] final: fix rabbi trader --- packages/client-twitter/src/base.ts | 2 +- packages/plugin-coinmarketcap/README.md | 2 +- packages/plugin-coinprice/README.md | 2 +- packages/plugin-letzai/README.md | 2 +- packages/plugin-node/README.md | 2 +- .../src/example/NAVALS-VAULT.md | 2 +- .../src/actions/analyzeTrade.ts | 142 +- packages/plugin-rabbi-trader/src/index.ts | 1996 +++++++++-------- .../src/services/simulationService.ts | 15 +- .../plugin-rabbi-trader/src/tokenUtils.ts | 28 +- packages/plugin-rabbi-trader/src/utils.ts | 278 +-- packages/plugin-rabbi-trader/src/wallet.ts | 479 ++-- packages/plugin-solana/src/index.ts | 3 +- pnpm-lock.yaml | 231 +- 14 files changed, 1669 insertions(+), 1515 deletions(-) diff --git a/packages/client-twitter/src/base.ts b/packages/client-twitter/src/base.ts index 5ad8b67039f..f49516dc8c4 100644 --- a/packages/client-twitter/src/base.ts +++ b/packages/client-twitter/src/base.ts @@ -361,7 +361,7 @@ export class ClientBase extends EventEmitter { .slice(0, count); // TODO: Once the 'count' parameter is fixed in the 'fetchTimeline' method of the 'agent-twitter-client', // this workaround can be removed. - // Related issue: https://github.com/elizaOS/agent-twitter-client/issues/43 + // Related issue: https://github.com/elizaos/agent-twitter-client/issues/43 } async fetchSearchTweets( diff --git a/packages/plugin-coinmarketcap/README.md b/packages/plugin-coinmarketcap/README.md index 08e62948826..9c042d9e576 100644 --- a/packages/plugin-coinmarketcap/README.md +++ b/packages/plugin-coinmarketcap/README.md @@ -124,4 +124,4 @@ For support, please open an issue in the repository or reach out to the maintain - [CoinMarketCap API Documentation](https://coinmarketcap.com/api/documentation/v1/) -- [GitHub Repository](https://github.com/elizaOS/eliza/tree/main/packages/plugin-coinmarketcap) +- [GitHub Repository](https://github.com/elizaos/eliza/tree/main/packages/plugin-coinmarketcap) diff --git a/packages/plugin-coinprice/README.md b/packages/plugin-coinprice/README.md index 97644a2d6e5..63ab6aa0448 100644 --- a/packages/plugin-coinprice/README.md +++ b/packages/plugin-coinprice/README.md @@ -131,4 +131,4 @@ For support, please open an issue in the repository or reach out to the maintain - [CoinGecko API Documentation](https://www.coingecko.com/en/api) - [CoinCap API Documentation](https://docs.coincap.io/) - [CoinMarketCap API Documentation](https://coinmarketcap.com/api/documentation/v1/) -- [GitHub Repository](https://github.com/elizaOS/eliza/tree/main/packages/plugin-coinprice) +- [GitHub Repository](https://github.com/elizaos/eliza/tree/main/packages/plugin-coinprice) diff --git a/packages/plugin-letzai/README.md b/packages/plugin-letzai/README.md index 7d21df07e3b..2e86b4228a5 100644 --- a/packages/plugin-letzai/README.md +++ b/packages/plugin-letzai/README.md @@ -2,7 +2,7 @@ ![LetzAI Logo](https://letz.ai/_next/image?url=%2FL.png&w=64&q=100) -A plugin to integrate LetzAI Image Generation capabilities into the elizaOS ecosystem. +A plugin to integrate LetzAI Image Generation capabilities into the elizaos ecosystem. It uses the [LetzAI API](https://www.letz.ai/docs/api) and can use any models available to API user. diff --git a/packages/plugin-node/README.md b/packages/plugin-node/README.md index 99a5f098508..7b6bfb1bcba 100644 --- a/packages/plugin-node/README.md +++ b/packages/plugin-node/README.md @@ -65,7 +65,7 @@ import { createNodePlugin } from "@elizaos/plugin-node"; const nodePlugin = createNodePlugin(); // Register with Eliza OS -elizaOS.registerPlugin(nodePlugin); +elizaos.registerPlugin(nodePlugin); ``` ## Services diff --git a/packages/plugin-obsidian/src/example/NAVALS-VAULT.md b/packages/plugin-obsidian/src/example/NAVALS-VAULT.md index 19731e46ea5..0c48934dcfd 100644 --- a/packages/plugin-obsidian/src/example/NAVALS-VAULT.md +++ b/packages/plugin-obsidian/src/example/NAVALS-VAULT.md @@ -31,7 +31,7 @@ https://drive.google.com/drive/folders/1EZiUhASpNQBYka3Z8NNkBzYnrb7TCfmG - Install the Obsidian Rest API plugin and activate it - Copy the API token from the plugin settings - Setup the agent with the API token and the Vault Rest API URL -- Run the elizaOS agent +- Run the elizaos agent - Prompt the agent to create the knowledge base (Take a couple minutes to complete): **"Create knowledge base"** Have fun talking to Naval's digital brain! diff --git a/packages/plugin-rabbi-trader/src/actions/analyzeTrade.ts b/packages/plugin-rabbi-trader/src/actions/analyzeTrade.ts index 574af302852..12fc6fd8365 100644 --- a/packages/plugin-rabbi-trader/src/actions/analyzeTrade.ts +++ b/packages/plugin-rabbi-trader/src/actions/analyzeTrade.ts @@ -1,47 +1,47 @@ import { - Action, - composeContext, - elizaLogger, - generateText, - ModelClass, - parseJSONObjectFromText, -} from "@elizaOS/core"; + Action, + composeContext, + elizaLogger, + generateText, + ModelClass, + parseJSONObjectFromText, +} from "@elizaos/core"; export const analyzeTradeAction: Action = { - name: "ANALYZE_TRADE", - description: "Analyze a token for trading opportunities", - similes: [ - "ANALYZE", - "ANALYZE_TOKEN", - "TRADE", - "ANALYZE_TRADE", - "EVALUATE", - "ASSESS", - ], - examples: [], - validate: async () => true, - handler: async (runtime, memory, state, params, callback) => { - try { - // composeState - if (!state) { - state = await runtime.composeState(memory); - } else state = await runtime.updateRecentMessageState(state); + name: "ANALYZE_TRADE", + description: "Analyze a token for trading opportunities", + similes: [ + "ANALYZE", + "ANALYZE_TOKEN", + "TRADE", + "ANALYZE_TRADE", + "EVALUATE", + "ASSESS", + ], + examples: [], + validate: async () => true, + handler: async (runtime, memory, state, params, callback) => { + try { + // composeState + if (!state) { + state = await runtime.composeState(memory); + } else state = await runtime.updateRecentMessageState(state); - const tokenData = { - walletBalance: params.walletBalance, - tokenAddress: params.tokenAddress, - price: params.price, - volume: params.volume, - marketCap: params.marketCap, - liquidity: params.liquidity, - holderDistribution: params.holderDistribution, - trustScore: params.trustScore, - dexscreener: params.dexscreener, - position: params.position, - }; + const tokenData = { + walletBalance: params.walletBalance, + tokenAddress: params.tokenAddress, + price: params.price, + volume: params.volume, + marketCap: params.marketCap, + liquidity: params.liquidity, + holderDistribution: params.holderDistribution, + trustScore: params.trustScore, + dexscreener: params.dexscreener, + position: params.position, + }; - // Direct prompt instead of template - const prompt = `Analyze the following token data and provide a trading recommendation. + // Direct prompt instead of template + const prompt = `Analyze the following token data and provide a trading recommendation. Return the response as a JSON object with the following structure: { "recommendation": "BUY" | "SELL" | "HOLD", @@ -54,41 +54,41 @@ Return the response as a JSON object with the following structure: Token Data: ${JSON.stringify(tokenData, null, 2)}`; - // Generate analysis using direct prompt - const content = await generateText({ - runtime, - context: prompt, - modelClass: ModelClass.LARGE, - }); + // Generate analysis using direct prompt + const content = await generateText({ + runtime, + context: prompt, + modelClass: ModelClass.LARGE, + }); - if (!content) { - throw new Error("No analysis generated"); - } + if (!content) { + throw new Error("No analysis generated"); + } - elizaLogger.log(`Raw analysis response:`, content); + elizaLogger.log(`Raw analysis response:`, content); - // Parse the response to get the recommended action - const recommendation = parseJSONObjectFromText(content); - elizaLogger.log( - `Parsed recommendation for ${params.tokenAddress}:`, - recommendation, - ); + // Parse the response to get the recommended action + const recommendation = parseJSONObjectFromText(content); + elizaLogger.log( + `Parsed recommendation for ${params.tokenAddress}:`, + recommendation + ); - // Send result through callback - if (callback) { - await callback({ - text: JSON.stringify(recommendation), - type: "analysis", - }); - } + // Send result through callback + if (callback) { + await callback({ + text: JSON.stringify(recommendation), + type: "analysis", + }); + } - return true; - } catch (error) { - elizaLogger.error(`Analysis failed:`, { - error: error instanceof Error ? error.message : "Unknown error", - stack: error instanceof Error ? error.stack : undefined, - }); - return false; - } - }, + return true; + } catch (error) { + elizaLogger.error(`Analysis failed:`, { + error: error instanceof Error ? error.message : "Unknown error", + stack: error instanceof Error ? error.stack : undefined, + }); + return false; + } + }, }; diff --git a/packages/plugin-rabbi-trader/src/index.ts b/packages/plugin-rabbi-trader/src/index.ts index 434311e4867..14c686afecc 100644 --- a/packages/plugin-rabbi-trader/src/index.ts +++ b/packages/plugin-rabbi-trader/src/index.ts @@ -1,1152 +1,1218 @@ -import type { Plugin, IAgentRuntime, Memory, State } from "@elizaOS/core"; -import { elizaLogger, settings } from "@elizaOS/core"; +import type { Plugin, IAgentRuntime, Memory, State } from "@elizaos/core"; +import { elizaLogger, settings } from "@elizaos/core"; import { z } from "zod"; -import { TwitterClientInterface } from "@elizaOS/client-twitter"; +import { TwitterClientInterface } from "@elizaos/client-twitter"; import { - solanaPlugin, - trustScoreProvider, - trustEvaluator, -} from "@elizaOS/plugin-solana"; + solanaPlugin, + trustScoreProvider, + trustEvaluator, + getTokenBalance, +} from "@elizaos/plugin-solana"; import { TokenProvider } from "./providers/token"; import { Connection, PublicKey } from "@solana/web3.js"; import type { Chain, WalletClient, Signature, Balance } from "@goat-sdk/core"; -import { getTokenBalance } from "@elizaOS/plugin-solana/src/providers/tokenUtils"; import * as fs from "fs"; import * as path from "path"; import { TrustScoreProvider } from "./providers/trustScoreProvider"; import { SimulationService } from "./services/simulationService"; import { SAFETY_LIMITS } from "./constants"; import NodeCache from "node-cache"; -import { TrustScoreDatabase } from "@elizaOS/packlages/plugin-trustdb"; +import { TrustScoreDatabase } from "@elizaos/plugin-trustdb"; import { v4 as uuidv4 } from "uuid"; import { actions } from "./actions"; import { - TradeAlert, - TradeBuyAlert, - tweetTrade, - TwitterConfigSchema, - TwitterService, + TradeAlert, + TradeBuyAlert, + tweetTrade, + TwitterConfigSchema, + TwitterService, } from "./services/twitter"; import { - executeTrade, - getChainWalletBalance, - getWalletBalance, - getWalletKeypair, + executeTrade, + getChainWalletBalance, + getWalletBalance, + getWalletKeypair, } from "./wallet"; import { ProcessedTokenData } from "./types"; import { analyzeTradeAction } from "./actions/analyzeTrade"; // Update Balance interface to include formatted interface ExtendedBalance extends Balance { - formatted: string; + formatted: string; } // Extended WalletProvider interface to ensure proper typing interface ExtendedWalletProvider extends WalletClient { - connection: Connection; - signMessage(message: string): Promise; - getFormattedPortfolio: (runtime: IAgentRuntime) => Promise; - balanceOf: (tokenAddress: string) => Promise; - getMaxBuyAmount: (tokenAddress: string) => Promise; - executeTrade: (params: { - tokenIn: string; - tokenOut: string; - amountIn: number; - slippage: number; - }) => Promise; + connection: Connection; + signMessage(message: string): Promise; + getFormattedPortfolio: (runtime: IAgentRuntime) => Promise; + balanceOf: (tokenAddress: string) => Promise; + getMaxBuyAmount: (tokenAddress: string) => Promise; + executeTrade: (params: { + tokenIn: string; + tokenOut: string; + amountIn: number; + slippage: number; + }) => Promise; } const REQUIRED_SETTINGS = { - WALLET_PUBLIC_KEY: "Solana wallet public key", - DEXSCREENER_WATCHLIST_ID: "DexScreener watchlist ID", - COINGECKO_API_KEY: "CoinGecko API key", + WALLET_PUBLIC_KEY: "Solana wallet public key", + DEXSCREENER_WATCHLIST_ID: "DexScreener watchlist ID", + COINGECKO_API_KEY: "CoinGecko API key", } as const; // Add near the top imports interface ExtendedPlugin extends Plugin { - name: string; - description: string; - evaluators: any[]; - providers: any[]; - actions: any[]; - services: any[]; - autoStart?: boolean; + name: string; + description: string; + evaluators: any[]; + providers: any[]; + actions: any[]; + services: any[]; + autoStart?: boolean; } // Add this helper function function validateSolanaAddress(address: string | undefined): boolean { - if (!address) return false; - try { - // Handle Solana addresses - if (!/^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(address)) { - elizaLogger.warn(`Solana address failed format check: ${address}`); - return false; - } + if (!address) return false; + try { + // Handle Solana addresses + if (!/^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(address)) { + elizaLogger.warn(`Solana address failed format check: ${address}`); + return false; + } - // Verify it's a valid Solana public key - const pubKey = new PublicKey(address); - const isValid = Boolean(pubKey.toBase58()); - elizaLogger.log( - `Solana address validation result for ${address}: ${isValid}` - ); - return isValid; - } catch (error) { - elizaLogger.error(`Address validation error for ${address}:`, error); - return false; - } + // Verify it's a valid Solana public key + const pubKey = new PublicKey(address); + const isValid = Boolean(pubKey.toBase58()); + elizaLogger.log( + `Solana address validation result for ${address}: ${isValid}` + ); + return isValid; + } catch (error) { + elizaLogger.error(`Address validation error for ${address}:`, error); + return false; + } } // Add function to load token addresses export function loadTokenAddresses(): string[] { - try { - const filePath = path.resolve( - process.cwd(), - "../characters/tokens/tokenaddresses.json" - ); - const data = fs.readFileSync(filePath, "utf8"); - const addresses = JSON.parse(data); + try { + const filePath = path.resolve( + process.cwd(), + "../characters/tokens/tokenaddresses.json" + ); + const data = fs.readFileSync(filePath, "utf8"); + const addresses = JSON.parse(data); - // Validate addresses - const validAddresses = addresses.filter((addr: string) => { - // Solana address validation - return validateSolanaAddress(addr); - }); + // Validate addresses + const validAddresses = addresses.filter((addr: string) => { + // Solana address validation + return validateSolanaAddress(addr); + }); - elizaLogger.log("Loaded token addresses:", { - total: validAddresses.length, - solana: validAddresses.filter((addr) => !addr.startsWith("0x")).length, - base: validAddresses.filter((addr) => addr.startsWith("0x")).length, - }); + elizaLogger.log("Loaded token addresses:", { + total: validAddresses.length, + solana: validAddresses.filter((addr) => !addr.startsWith("0x")) + .length, + base: validAddresses.filter((addr) => addr.startsWith("0x")).length, + }); - return validAddresses; - } catch (error) { - elizaLogger.error("Failed to load token addresses:", error); - throw new Error("Token addresses file not found or invalid"); - } + return validAddresses; + } catch (error) { + elizaLogger.error("Failed to load token addresses:", error); + throw new Error("Token addresses file not found or invalid"); + } } // Add cache configuration after other interfaces interface CacheEntry { - lastAnalysis: number; - tokenData: any; - trustScore: number; - analysisResult: any; + lastAnalysis: number; + tokenData: any; + trustScore: number; + analysisResult: any; } // Add cache instance before createGoatPlugin const tokenCache = new NodeCache({ - stdTTL: 1200, // 20 minutes in seconds - checkperiod: 120, // Check for expired entries every 2 minutes + stdTTL: 1200, // 20 minutes in seconds + checkperiod: 120, // Check for expired entries every 2 minutes }); // Add near the top with other interfaces interface SkipWaitCache { - lastTweet: number; - action: "WAIT" | "SKIP"; + lastTweet: number; + action: "WAIT" | "SKIP"; } // Add near other cache instances const skipWaitCache = new NodeCache({ - stdTTL: 7200, // 2 hours in seconds - checkperiod: 600, // Check for expired entries every 10 minutes + stdTTL: 7200, // 2 hours in seconds + checkperiod: 600, // Check for expired entries every 10 minutes }); // Add near other interfaces interface TweetRateLimit { - lastTweet: number; - count: number; // Track number of tweets in the time window + lastTweet: number; + count: number; // Track number of tweets in the time window } // Add near other cache instances const tweetRateCache = new NodeCache({ - stdTTL: 86400, // 24 hours in seconds - checkperiod: 3600, // Check every hour + stdTTL: 86400, // 24 hours in seconds + checkperiod: 3600, // Check every hour }); // Add helper function function canTweet(tweetType: "trade" | "market_search"): boolean { - const now = Date.now(); - const hourKey = `tweets_${tweetType}_${Math.floor(now / 3600000)}`; // Key by hour and type - const rateLimit: TweetRateLimit = tweetRateCache.get(hourKey) || { - lastTweet: now, - count: 0, - }; - - // Different limits for different tweet types - const MAX_TWEETS_PER_HOUR = { - trade: 10, - market_search: 10, // Lower limit for market search tweets - }; - - if (rateLimit.count >= MAX_TWEETS_PER_HOUR[tweetType]) { - elizaLogger.warn( - `Tweet rate limit reached for ${tweetType}: ${rateLimit.count} tweets this hour` - ); - return false; - } + const now = Date.now(); + const hourKey = `tweets_${tweetType}_${Math.floor(now / 3600000)}`; // Key by hour and type + const rateLimit: TweetRateLimit = tweetRateCache.get(hourKey) || { + lastTweet: now, + count: 0, + }; + + // Different limits for different tweet types + const MAX_TWEETS_PER_HOUR = { + trade: 10, + market_search: 10, // Lower limit for market search tweets + }; + + if (rateLimit.count >= MAX_TWEETS_PER_HOUR[tweetType]) { + elizaLogger.warn( + `Tweet rate limit reached for ${tweetType}: ${rateLimit.count} tweets this hour` + ); + return false; + } - // Update rate limit - tweetRateCache.set(hourKey, { - lastTweet: now, - count: rateLimit.count + 1, - }); + // Update rate limit + tweetRateCache.set(hourKey, { + lastTweet: now, + count: rateLimit.count + 1, + }); - return true; + return true; } // Add new interfaces near the top with other interfaces interface TradePerformance { - token_address: string; - recommender_id: string; - buy_price: number; - sell_price: number; - buy_timeStamp: string; - sell_timeStamp: string; - buy_amount: number; - sell_amount: number; - buy_value_usd: number; - sell_value_usd: number; - buy_market_cap: number; - sell_market_cap: number; - buy_liquidity: number; - sell_liquidity: number; - profit_usd: number; - profit_percent: number; - market_cap_change: number; - liquidity_change: number; - rapidDump: boolean; + token_address: string; + recommender_id: string; + buy_price: number; + sell_price: number; + buy_timeStamp: string; + sell_timeStamp: string; + buy_amount: number; + sell_amount: number; + buy_value_usd: number; + sell_value_usd: number; + buy_market_cap: number; + sell_market_cap: number; + buy_liquidity: number; + sell_liquidity: number; + profit_usd: number; + profit_percent: number; + market_cap_change: number; + liquidity_change: number; + rapidDump: boolean; } interface TradePosition { - token_address: string; - entry_price: number; - size: number; - stop_loss: number; - take_profit: number; - open_timeStamp: string; - close_timeStamp?: string; - status?: "OPEN" | "CLOSED"; + token_address: string; + entry_price: number; + size: number; + stop_loss: number; + take_profit: number; + open_timeStamp: string; + close_timeStamp?: string; + status?: "OPEN" | "CLOSED"; } // Update the analysisParams interface interface AnalysisParams extends Record { - walletBalance: number; - tokenAddress: string; - price: number; - volume: number; - marketCap: number; - liquidity: number; - holderDistribution: string; - trustScore: number; - dexscreener: any; - position?: TradePosition; - tradeHistory?: TradePerformance[]; + walletBalance: number; + tokenAddress: string; + price: number; + volume: number; + marketCap: number; + liquidity: number; + holderDistribution: string; + trustScore: number; + dexscreener: any; + position?: TradePosition; + tradeHistory?: TradePerformance[]; } // Update the interface to match the SQL parameter order interface SellDetailsData { - // SET clause parameters in order - sell_price: number; - sell_timeStamp: string; - sell_amount: number; - received_sol: number; - sell_value_usd: number; - profit_usd: number; - profit_percent: number; - sell_market_cap: number; - market_cap_change: number; - sell_liquidity: number; - liquidity_change: number; - rapidDump: boolean; - sell_recommender_id: string | null; + // SET clause parameters in order + sell_price: number; + sell_timeStamp: string; + sell_amount: number; + received_sol: number; + sell_value_usd: number; + profit_usd: number; + profit_percent: number; + sell_market_cap: number; + market_cap_change: number; + sell_liquidity: number; + liquidity_change: number; + rapidDump: boolean; + sell_recommender_id: string | null; } async function updateSellDetails( - runtime: IAgentRuntime, - tokenAddress: string, - recommenderId: string, - tradeAmount: number, - latestTrade: any, - tokenData: any + runtime: IAgentRuntime, + tokenAddress: string, + recommenderId: string, + tradeAmount: number, + latestTrade: any, + tokenData: any ) { - const trustScoreDb = new TrustScoreDatabase(runtime.databaseAdapter.db); - - const trade = await trustScoreDb.getLatestTradePerformance( - tokenAddress, - recommenderId, - false - ); - - if (!trade) { - elizaLogger.error( - `No trade found for token ${tokenAddress} and recommender ${recommenderId}` - ); - throw new Error("No trade found to update"); - } - - const currentPrice = tokenData.dexScreenerData.pairs[0]?.priceUsd || 0; - const marketCap = tokenData.dexScreenerData.pairs[0]?.marketCap || 0; - const liquidity = tokenData.dexScreenerData.pairs[0]?.liquidity?.usd || 0; - - const sellValueUsd = tradeAmount * Number(currentPrice); - const profitUsd = sellValueUsd - trade.buy_value_usd; - const profitPercent = (profitUsd / trade.buy_value_usd) * 100; - - // Create sellDetailsData object matching SQL parameter order - const sellDetails: SellDetailsData = { - sell_price: Number(currentPrice), - sell_timeStamp: new Date().toISOString(), - sell_amount: tradeAmount, - received_sol: tradeAmount, - sell_value_usd: sellValueUsd, - profit_usd: profitUsd, - profit_percent: profitPercent, - sell_market_cap: marketCap, - market_cap_change: marketCap - trade.buy_market_cap, - sell_liquidity: liquidity, - liquidity_change: liquidity - trade.buy_liquidity, - rapidDump: false, - sell_recommender_id: recommenderId || null, - }; - - elizaLogger.log("Attempting to update trade performance with data:", { - sellDetails, - whereClause: { - tokenAddress, - recommenderId, - buyTimeStamp: trade.buy_timeStamp, - }, - isSimulation: false, - }); - - try { - try { - // Pass sellDetails first (SET clause), then WHERE clause parameters - elizaLogger.log( - "Verifying parameters for updateTradePerformanceOnSell:", - { - sellDetails, - tokenAddress, - recommenderId, - buyTimeStamp: trade.buy_timeStamp, - isSimulation: false, - } - ); - - const success = await trustScoreDb.updateTradePerformanceOnSell( - tokenAddress, // 1. WHERE token_address = ? - recommenderId, // 2. WHERE recommender_id = ? - trade.buy_timeStamp, // 3. WHERE buy_timeStamp = ? - sellDetails, // 4. SET clause parameters - false // 5. isSimulation flag - ); - - if (!success) { - elizaLogger.warn("Trade update returned false", { - tokenAddress, - recommenderId, - buyTimeStamp: trade.buy_timeStamp, - }); - } + const trustScoreDb = new TrustScoreDatabase(runtime.databaseAdapter.db); - elizaLogger.log("Trade performance update completed", { - success, + const trade = await trustScoreDb.getLatestTradePerformance( tokenAddress, recommenderId, - profitPercent: profitPercent.toFixed(2) + "%", - profitUsd: profitUsd.toFixed(4) + " USD", - }); - } catch (dbError) { - elizaLogger.error("Database error during trade update:", { - error: dbError, - query: { - sellDetails, - whereClause: { + false + ); + + if (!trade) { + elizaLogger.error( + `No trade found for token ${tokenAddress} and recommender ${recommenderId}` + ); + throw new Error("No trade found to update"); + } + + const currentPrice = tokenData.dexScreenerData.pairs[0]?.priceUsd || 0; + const marketCap = tokenData.dexScreenerData.pairs[0]?.marketCap || 0; + const liquidity = tokenData.dexScreenerData.pairs[0]?.liquidity?.usd || 0; + + const sellValueUsd = tradeAmount * Number(currentPrice); + const profitUsd = sellValueUsd - trade.buy_value_usd; + const profitPercent = (profitUsd / trade.buy_value_usd) * 100; + + // Create sellDetailsData object matching SQL parameter order + const sellDetails: SellDetailsData = { + sell_price: Number(currentPrice), + sell_timeStamp: new Date().toISOString(), + sell_amount: tradeAmount, + received_sol: tradeAmount, + sell_value_usd: sellValueUsd, + profit_usd: profitUsd, + profit_percent: profitPercent, + sell_market_cap: marketCap, + market_cap_change: marketCap - trade.buy_market_cap, + sell_liquidity: liquidity, + liquidity_change: liquidity - trade.buy_liquidity, + rapidDump: false, + sell_recommender_id: recommenderId || null, + }; + + elizaLogger.log("Attempting to update trade performance with data:", { + sellDetails, + whereClause: { tokenAddress, recommenderId, buyTimeStamp: trade.buy_timeStamp, - }, }, - }); - throw dbError; + isSimulation: false, + }); + + try { + try { + // Pass sellDetails first (SET clause), then WHERE clause parameters + elizaLogger.log( + "Verifying parameters for updateTradePerformanceOnSell:", + { + sellDetails, + tokenAddress, + recommenderId, + buyTimeStamp: trade.buy_timeStamp, + isSimulation: false, + } + ); + + const success = await trustScoreDb.updateTradePerformanceOnSell( + tokenAddress, // 1. WHERE token_address = ? + recommenderId, // 2. WHERE recommender_id = ? + trade.buy_timeStamp, // 3. WHERE buy_timeStamp = ? + sellDetails, // 4. SET clause parameters + false // 5. isSimulation flag + ); + + if (!success) { + elizaLogger.warn("Trade update returned false", { + tokenAddress, + recommenderId, + buyTimeStamp: trade.buy_timeStamp, + }); + } + + elizaLogger.log("Trade performance update completed", { + success, + tokenAddress, + recommenderId, + profitPercent: profitPercent.toFixed(2) + "%", + profitUsd: profitUsd.toFixed(4) + " USD", + }); + } catch (dbError) { + elizaLogger.error("Database error during trade update:", { + error: dbError, + query: { + sellDetails, + whereClause: { + tokenAddress, + recommenderId, + buyTimeStamp: trade.buy_timeStamp, + }, + }, + }); + throw dbError; + } + } catch (error) { + elizaLogger.error("Failed to update trade performance:", { + error, + parameters: { + sellDetails, + whereClause: { + tokenAddress, + recommenderId, + buyTimeStamp: trade.buy_timeStamp, + }, + originalTrade: trade, + }, + errorDetails: + error instanceof Error + ? { + message: error.message, + stack: error.stack, + name: error.name, + } + : error, + }); + throw error; } - } catch (error) { - elizaLogger.error("Failed to update trade performance:", { - error, - parameters: { + + return { sellDetails, - whereClause: { - tokenAddress, - recommenderId, - buyTimeStamp: trade.buy_timeStamp, + currentPrice, + profitDetails: { + profitUsd, + profitPercent, + sellValueUsd, }, - originalTrade: trade, - }, - errorDetails: - error instanceof Error - ? { - message: error.message, - stack: error.stack, - name: error.name, - } - : error, - }); - throw error; - } - - return { - sellDetails, - currentPrice, - profitDetails: { - profitUsd, - profitPercent, - sellValueUsd, - }, - }; + }; } // Update the module declaration to match the new parameter order declare module "@elizaos/plugin-trustdb" { - interface TrustScoreDatabase { - updateTradePerformanceOnSell( - tokenAddress: string, // Changed order: tokenAddress first - recommenderId: string, // recommenderId second - buyTimeStamp: string, // buyTimeStamp third - sellDetails: SellDetailsData, // sellDetails fourth - isSimulation: boolean // isSimulation fifth - ): boolean; - } + interface TrustScoreDatabase { + updateTradePerformanceOnSell( + tokenAddress: string, // Changed order: tokenAddress first + recommenderId: string, // recommenderId second + buyTimeStamp: string, // buyTimeStamp third + sellDetails: SellDetailsData, // sellDetails fourth + isSimulation: boolean // isSimulation fifth + ): boolean; + } } async function getChainBalance( - connection: Connection, - walletAddress: PublicKey, - tokenAddress: string + connection: Connection, + walletAddress: PublicKey, + tokenAddress: string ): Promise { - // Use existing Solana balance fetching logic - return await getTokenBalance( - connection, - walletAddress, - new PublicKey(tokenAddress) - ); + // Use existing Solana balance fetching logic + return await getTokenBalance( + connection, + walletAddress, + new PublicKey(tokenAddress) + ); } async function createRabbiTraderPlugin( - getSetting: (key: string) => string | undefined, - runtime?: IAgentRuntime + getSetting: (key: string) => string | undefined, + runtime?: IAgentRuntime ): Promise { - // Define resumeTrading at the start of the function - const resumeTrading = async () => { - // Load and analyze tokens - const tokenAddresses = loadTokenAddresses().filter( - (addr) => !addr.startsWith("0x") - ); - elizaLogger.log(`Analyzing ${tokenAddresses.length} Solana tokens...`); + // Define resumeTrading at the start of the function + const resumeTrading = async () => { + // Load and analyze tokens + const tokenAddresses = loadTokenAddresses().filter( + (addr) => !addr.startsWith("0x") + ); + elizaLogger.log(`Analyzing ${tokenAddresses.length} Solana tokens...`); + + // Analyze regular token list + for (const tokenAddress of tokenAddresses) { + await analyzeToken( + runtime, + connection, + twitterService, + tokenAddress + ); + } - // Analyze regular token list - for (const tokenAddress of tokenAddresses) { - await analyzeToken(runtime, connection, twitterService, tokenAddress); - } + // Add delay between iterations + await new Promise((resolve) => setTimeout(resolve, 1200000)); // 20 minutes + }; - // Add delay between iterations - await new Promise((resolve) => setTimeout(resolve, 1200000)); // 20 minutes - }; + elizaLogger.log("Starting GOAT plugin initialization"); - elizaLogger.log("Starting GOAT plugin initialization"); + // Move connection initialization to the top + const connection = new Connection( + runtime?.getSetting("RPC_URL") || "https://api.mainnet-beta.solana.com" + ); - // Move connection initialization to the top - const connection = new Connection( - runtime?.getSetting("RPC_URL") || "https://api.mainnet-beta.solana.com" - ); + const keypair = getWalletKeypair(runtime); - const keypair = getWalletKeypair(runtime); + // Validate required settings + const missingSettings: string[] = []; + for (const [key, description] of Object.entries(REQUIRED_SETTINGS)) { + if (!getSetting(key)) { + missingSettings.push(`${key} (${description})`); + } + } - // Validate required settings - const missingSettings: string[] = []; - for (const [key, description] of Object.entries(REQUIRED_SETTINGS)) { - if (!getSetting(key)) { - missingSettings.push(`${key} (${description})`); + if (missingSettings.length > 0) { + const errorMsg = `Missing required settings: ${missingSettings.join(", ")}`; + elizaLogger.error(errorMsg); + throw new Error(errorMsg); } - } - - if (missingSettings.length > 0) { - const errorMsg = `Missing required settings: ${missingSettings.join(", ")}`; - elizaLogger.error(errorMsg); - throw new Error(errorMsg); - } - - elizaLogger.log("Initializing Solana connection..."); - let walletProvider: ExtendedWalletProvider = { - connection, - getChain: () => ({ type: "solana" }), - getAddress: () => keypair.publicKey.toBase58(), - signMessage: async (message: string): Promise => { - throw new Error("Message signing not implemented for Solana wallet"); - }, - balanceOf: async (tokenAddress: string): Promise => { - try { - if (tokenAddress.startsWith("0x")) { - // Handle Base token balance - const baseBalance = await getChainBalance( - connection, - keypair.publicKey, - tokenAddress - ); - return { - value: BigInt(baseBalance.toString()), - decimals: 18, // Base uses 18 decimals - formatted: (baseBalance / 1e18).toString(), - symbol: "ETH", - name: "Base", - }; - } else { - // Existing Solana logic - const tokenPublicKey = new PublicKey(tokenAddress); - const amount = await getTokenBalance( - connection, - keypair.publicKey, - tokenPublicKey - ); - return { - value: BigInt(amount.toString()), - decimals: 9, - formatted: (amount / 1e9).toString(), - symbol: "SOL", - name: "Solana", - }; - } - } catch (error) { - return { - value: BigInt(0), - decimals: tokenAddress.startsWith("0x") ? 18 : 9, - formatted: "0", - symbol: tokenAddress.startsWith("0x") ? "ETH" : "SOL", - name: tokenAddress.startsWith("0x") ? "Base" : "Solana", - }; - } - }, - getMaxBuyAmount: async (tokenAddress: string) => { - try { - if (tokenAddress.startsWith("0x")) { - // Handle Base chain balance - const baseBalance = await getChainBalance( - connection, - keypair.publicKey, - tokenAddress - ); - return (baseBalance * 0.9) / 1e18; // Base uses 18 decimals - } else { - // Handle Solana balance - const balance = await connection.getBalance(keypair.publicKey); - return (balance * 0.9) / 1e9; // Solana uses 9 decimals - } - } catch (error) { - elizaLogger.error( - `Failed to get max buy amount for ${tokenAddress}:`, - error + + elizaLogger.log("Initializing Solana connection..."); + let walletProvider: ExtendedWalletProvider = { + connection, + getChain: () => ({ type: "solana" }), + getAddress: () => keypair.publicKey.toBase58(), + signMessage: async (message: string): Promise => { + throw new Error( + "Message signing not implemented for Solana wallet" + ); + }, + balanceOf: async (tokenAddress: string): Promise => { + try { + if (tokenAddress.startsWith("0x")) { + // Handle Base token balance + const baseBalance = await getChainBalance( + connection, + keypair.publicKey, + tokenAddress + ); + return { + value: BigInt(baseBalance.toString()), + decimals: 18, // Base uses 18 decimals + formatted: (baseBalance / 1e18).toString(), + symbol: "ETH", + name: "Base", + }; + } else { + // Existing Solana logic + const tokenPublicKey = new PublicKey(tokenAddress); + const amount = await getTokenBalance( + connection, + keypair.publicKey, + tokenPublicKey + ); + return { + value: BigInt(amount.toString()), + decimals: 9, + formatted: (amount / 1e9).toString(), + symbol: "SOL", + name: "Solana", + }; + } + } catch (error) { + return { + value: BigInt(0), + decimals: tokenAddress.startsWith("0x") ? 18 : 9, + formatted: "0", + symbol: tokenAddress.startsWith("0x") ? "ETH" : "SOL", + name: tokenAddress.startsWith("0x") ? "Base" : "Solana", + }; + } + }, + getMaxBuyAmount: async (tokenAddress: string) => { + try { + if (tokenAddress.startsWith("0x")) { + // Handle Base chain balance + const baseBalance = await getChainBalance( + connection, + keypair.publicKey, + tokenAddress + ); + return (baseBalance * 0.9) / 1e18; // Base uses 18 decimals + } else { + // Handle Solana balance + const balance = await connection.getBalance( + keypair.publicKey + ); + return (balance * 0.9) / 1e9; // Solana uses 9 decimals + } + } catch (error) { + elizaLogger.error( + `Failed to get max buy amount for ${tokenAddress}:`, + error + ); + return 0; + } + }, + executeTrade: async (params) => { + try { + return { success: true }; + } catch (error) { + throw error; + } + }, + getFormattedPortfolio: async () => "", + }; + + elizaLogger.log( + "Solana connection and wallet provider initialized successfully" + ); + + // Initialize Twitter service if enabled + let twitterService: TwitterService | undefined; + try { + elizaLogger.log( + "Configuring Twitter service for trade notifications..." ); - return 0; - } - }, - executeTrade: async (params) => { - try { - return { success: true }; - } catch (error) { - throw error; - } - }, - getFormattedPortfolio: async () => "", - }; - - elizaLogger.log( - "Solana connection and wallet provider initialized successfully" - ); - - // Initialize Twitter service if enabled - let twitterService: TwitterService | undefined; - try { - elizaLogger.log("Configuring Twitter service for trade notifications..."); - const twitterConfig = TwitterConfigSchema.parse({ - enabled: getSetting("TWITTER_ENABLED") === "true", - username: getSetting("TWITTER_USERNAME"), - dryRun: false, - }); + const twitterConfig = TwitterConfigSchema.parse({ + enabled: getSetting("TWITTER_ENABLED") === "true", + username: getSetting("TWITTER_USERNAME"), + dryRun: false, + }); - if (twitterConfig.enabled && runtime) { - elizaLogger.log("Starting Twitter client initialization..."); - const twitterClient = await TwitterClientInterface.start(runtime); - twitterService = new TwitterService(twitterClient, twitterConfig); + if (twitterConfig.enabled && runtime) { + elizaLogger.log("Starting Twitter client initialization..."); + const twitterClient = await TwitterClientInterface.start(runtime); + twitterService = new TwitterService(twitterClient, twitterConfig); - // Add delay after initialization - await new Promise((resolve) => setTimeout(resolve, 5000)); + // Add delay after initialization + await new Promise((resolve) => setTimeout(resolve, 5000)); - elizaLogger.log("Twitter service initialized successfully", { - username: twitterConfig.username, - dryRun: twitterConfig.dryRun, - }); + elizaLogger.log("Twitter service initialized successfully", { + username: twitterConfig.username, + dryRun: twitterConfig.dryRun, + }); + } + } catch (error) { + elizaLogger.error("Failed to initialize Twitter service:", error); } - } catch (error) { - elizaLogger.error("Failed to initialize Twitter service:", error); - } - - elizaLogger.log("Initializing Solana plugin components..."); - - try { - const customActions = actions; - - // Then update the plugin creation - const plugin: ExtendedPlugin = { - name: "[Rabbi Trader] Onchain Actions with Solana Integration", - description: "Autonomous trading integration with AI analysis", - evaluators: [trustEvaluator, ...(solanaPlugin.evaluators || [])], - providers: [ - walletProvider, - trustScoreProvider, - ...(solanaPlugin.providers || []), - ], - actions: [...customActions, ...(solanaPlugin.actions || [])], - services: [], - autoStart: true, - }; - // Add auto-start trading analysis - if (!runtime) return; + elizaLogger.log("Initializing Solana plugin components..."); - elizaLogger.log("Starting autonomous trading system..."); - const analyzeTradeAction = plugin.actions.find( - (a) => a.name === "ANALYZE_TRADE" - ); + try { + const customActions = actions; + + // Then update the plugin creation + const plugin: ExtendedPlugin = { + name: "[Rabbi Trader] Onchain Actions with Solana Integration", + description: "Autonomous trading integration with AI analysis", + evaluators: [trustEvaluator, ...(solanaPlugin.evaluators || [])], + providers: [ + walletProvider, + trustScoreProvider, + ...(solanaPlugin.providers || []), + ], + actions: [...customActions, ...(solanaPlugin.actions || [])], + services: [], + autoStart: true, + }; - if (!analyzeTradeAction) return; + // Add auto-start trading analysis + if (!runtime) return; - const interval = Number(runtime.getSetting("TRADING_INTERVAL")) || 300000; + elizaLogger.log("Starting autonomous trading system..."); + const analyzeTradeAction = plugin.actions.find( + (a) => a.name === "ANALYZE_TRADE" + ); - // Then start trading loop if enabled - if (!settings.ENABLE_TRADING) return; + if (!analyzeTradeAction) return; - elizaLogger.log("Initializing trading loop..."); - await resumeTrading(); - setInterval(resumeTrading, interval); + const interval = + Number(runtime.getSetting("TRADING_INTERVAL")) || 300000; - elizaLogger.log("GOAT plugin initialization completed successfully"); - return plugin; - } catch (error) { - elizaLogger.error("Failed to initialize plugin components:", error); - throw new Error( - `Plugin initialization failed: ${error instanceof Error ? error.message : String(error)}` - ); - } + // Then start trading loop if enabled + if (!settings.ENABLE_TRADING) return; + + elizaLogger.log("Initializing trading loop..."); + await resumeTrading(); + setInterval(resumeTrading, interval); + + elizaLogger.log("GOAT plugin initialization completed successfully"); + return plugin; + } catch (error) { + elizaLogger.error("Failed to initialize plugin components:", error); + throw new Error( + `Plugin initialization failed: ${error instanceof Error ? error.message : String(error)}` + ); + } } async function analyzeToken( - runtime: IAgentRuntime, - connection: Connection, - twitterService: TwitterService, - tokenAddress: string + runtime: IAgentRuntime, + connection: Connection, + twitterService: TwitterService, + tokenAddress: string ) { - try { - // Check cache first - const cachedData: CacheEntry | undefined = tokenCache.get(tokenAddress); - const now = Date.now(); + try { + // Check cache first + const cachedData: CacheEntry | undefined = tokenCache.get(tokenAddress); + const now = Date.now(); - // Skip if analyzed within last 20 minutes - if (cachedData && now - cachedData.lastAnalysis < 1200000) { - elizaLogger.log( - `Using cached data for ${tokenAddress}, last analyzed ${Math.floor((now - cachedData.lastAnalysis) / 1000)}s ago` - ); - return; - } + // Skip if analyzed within last 20 minutes + if (cachedData && now - cachedData.lastAnalysis < 1200000) { + elizaLogger.log( + `Using cached data for ${tokenAddress}, last analyzed ${Math.floor((now - cachedData.lastAnalysis) / 1000)}s ago` + ); + return; + } - elizaLogger.log(`Starting analysis for token: ${tokenAddress}`); + elizaLogger.log(`Starting analysis for token: ${tokenAddress}`); - await new Promise((resolve) => setTimeout(resolve, 2000)); + await new Promise((resolve) => setTimeout(resolve, 2000)); - if (!validateSolanaAddress(tokenAddress)) { - elizaLogger.error(`Invalid token address format: ${tokenAddress}`); - return; - } + if (!validateSolanaAddress(tokenAddress)) { + elizaLogger.error(`Invalid token address format: ${tokenAddress}`); + return; + } - // Initialize TokenProvider directly with just the token address - const tokenProvider = new TokenProvider(tokenAddress); - - // Get processed token data which includes DexScreener data - elizaLogger.log(`Fetching token data for ${tokenAddress}`); - const tokenData = await tokenProvider.getProcessedTokenData(); - elizaLogger.log(`Token data fetched for ${tokenAddress}:`, tokenData); - - // Get trust score and cache it - const trustProvider = new TrustScoreProvider(); - const trustEvaluation = await trustProvider.evaluateToken(tokenAddress); - const { trustScore } = trustEvaluation; - - // Cache the new data - const cacheEntry: CacheEntry = { - lastAnalysis: Date.now(), - tokenData, - trustScore, - analysisResult: null, // Will be updated after analysis - }; - tokenCache.set(tokenAddress, cacheEntry); + // Initialize TokenProvider directly with just the token address + const tokenProvider = new TokenProvider(tokenAddress); + + // Get processed token data which includes DexScreener data + elizaLogger.log(`Fetching token data for ${tokenAddress}`); + const tokenData = await tokenProvider.getProcessedTokenData(); + elizaLogger.log(`Token data fetched for ${tokenAddress}:`, tokenData); + + // Get trust score and cache it + const trustProvider = new TrustScoreProvider(); + const trustEvaluation = await trustProvider.evaluateToken(tokenAddress); + const { trustScore } = trustEvaluation; + + // Cache the new data + const cacheEntry: CacheEntry = { + lastAnalysis: Date.now(), + tokenData, + trustScore, + analysisResult: null, // Will be updated after analysis + }; + tokenCache.set(tokenAddress, cacheEntry); - const walletPublicKey = runtime.getSetting("WALLET_PUBLIC_KEY"); - if (!walletPublicKey) { - elizaLogger.error("No wallet public key configured"); - return; - } + const walletPublicKey = runtime.getSetting("WALLET_PUBLIC_KEY"); + if (!walletPublicKey) { + elizaLogger.error("No wallet public key configured"); + return; + } - const balance = await connection.getBalance(new PublicKey(walletPublicKey)); + const balance = await connection.getBalance( + new PublicKey(walletPublicKey) + ); - const walletSolBalance = { - formatted: (balance / 1e9).toString(), - }; + const walletSolBalance = { + formatted: (balance / 1e9).toString(), + }; - // Initialize trustScoreDb - const trustScoreDb = new TrustScoreDatabase(runtime.databaseAdapter.db); + // Initialize trustScoreDb + const trustScoreDb = new TrustScoreDatabase(runtime.databaseAdapter.db); - // Before creating analysisParams, get the latest trade performance - const latestTrade = trustScoreDb.getLatestTradePerformance( - tokenAddress, - runtime.agentId, - false // not simulation - ); + // Before creating analysisParams, get the latest trade performance + const latestTrade = trustScoreDb.getLatestTradePerformance( + tokenAddress, + runtime.agentId, + false // not simulation + ); - elizaLogger.log(`Latest trade for ${tokenAddress}:`, latestTrade); - - // Before creating analysisParams, get the correct chain balance - const walletBalance = await getChainWalletBalance(runtime, tokenAddress); - - const pair = tokenData.dexScreenerData.pairs[0]; - const analysisParams: AnalysisParams = { - walletBalance, // Now using the correct chain's balance - tokenAddress, - price: Number(pair?.priceUsd || 0), - volume: pair?.volume?.h24 || 0, - marketCap: pair?.marketCap || 0, - liquidity: pair?.liquidity?.usd || 0, - holderDistribution: tokenData.holderDistributionTrend, - trustScore: trustScore || 0, - dexscreener: tokenData.dexScreenerData, - position: latestTrade - ? { - token_address: latestTrade.token_address, - entry_price: latestTrade.buy_price, - size: latestTrade.buy_amount, - stop_loss: latestTrade.buy_price * 0.85, // 15% stop loss - take_profit: latestTrade.buy_price * 1.3, // 30% take profit - open_timeStamp: latestTrade.buy_timeStamp, - status: latestTrade.sell_timeStamp ? "CLOSED" : "OPEN", - } - : undefined, - }; + elizaLogger.log(`Latest trade for ${tokenAddress}:`, latestTrade); - // Create initial state first - const state: State = await runtime.composeState({ - userId: runtime.agentId, - agentId: runtime.agentId, - roomId: runtime.agentId, - content: { - text: `Initialize state for ${tokenAddress}`, - type: "analysis", - }, - }); + // Before creating analysisParams, get the correct chain balance + const walletBalance = await getChainWalletBalance( + runtime, + tokenAddress + ); - // Then create analysis memory using state - const analysisMemory: Memory = { - userId: state.userId, - agentId: runtime.agentId, - roomId: state.roomId, - content: { - text: `Analyze trade for ${tokenAddress}`, - type: "analysis", - }, - }; + const pair = tokenData.dexScreenerData.pairs[0]; + const analysisParams: AnalysisParams = { + walletBalance, // Now using the correct chain's balance + tokenAddress, + price: Number(pair?.priceUsd || 0), + volume: pair?.volume?.h24 || 0, + marketCap: pair?.marketCap || 0, + liquidity: pair?.liquidity?.usd || 0, + holderDistribution: tokenData.holderDistributionTrend, + trustScore: trustScore || 0, + dexscreener: tokenData.dexScreenerData, + position: latestTrade + ? { + token_address: latestTrade.token_address, + entry_price: latestTrade.buy_price, + size: latestTrade.buy_amount, + stop_loss: latestTrade.buy_price * 0.85, // 15% stop loss + take_profit: latestTrade.buy_price * 1.3, // 30% take profit + open_timeStamp: latestTrade.buy_timeStamp, + status: latestTrade.sell_timeStamp ? "CLOSED" : "OPEN", + } + : undefined, + }; - // Update analysis result in cache after completion - const analysisResult = await analyzeTradeAction.handler( - runtime, - analysisMemory, - state, - analysisParams, - async (response) => { - if (!response) { - elizaLogger.error(`Empty response from analysis for ${tokenAddress}`); - return []; - } + // Create initial state first + const state: State = await runtime.composeState({ + userId: runtime.agentId, + agentId: runtime.agentId, + roomId: runtime.agentId, + content: { + text: `Initialize state for ${tokenAddress}`, + type: "analysis", + }, + }); - elizaLogger.log(`Analysis result for ${tokenAddress}:`, response); - try { - // Parse the JSON response from the analysis - const result = - typeof response.text === "string" - ? JSON.parse(response.text) - : response.text; - - if (!result) { - elizaLogger.error(`Invalid analysis result for ${tokenAddress}`); - - return []; - } - - if (result.shouldTrade && result.recommendedAction === "BUY") { - await buy({ - result, - runtime, - state, - tokenAddress, - tokenData, - twitterService, - trustScore, - }); - } else if (result.recommendedAction === "SELL") { - await sell({ - latestTrade, - result, - runtime, - state, - tokenAddress, - tokenProvider, - trustScoreDb, - twitterService, - trustScore, - }); - } else { - elizaLogger.log( - `Trade not recommended for ${tokenAddress}:`, - result - ); - } - } catch (parseError) {} - return []; - } - ); - cacheEntry.analysisResult = analysisResult; - tokenCache.set(tokenAddress, cacheEntry); - } catch (tokenError) { - elizaLogger.error(`Error processing token ${tokenAddress}:`, { - error: tokenError, - stack: tokenError instanceof Error ? tokenError.stack : undefined, - }); - await new Promise((resolve) => setTimeout(resolve, 2000)); - } + // Then create analysis memory using state + const analysisMemory: Memory = { + userId: state.userId, + agentId: runtime.agentId, + roomId: state.roomId, + content: { + text: `Analyze trade for ${tokenAddress}`, + type: "analysis", + }, + }; + + // Update analysis result in cache after completion + const analysisResult = await analyzeTradeAction.handler( + runtime, + analysisMemory, + state, + analysisParams, + async (response) => { + if (!response) { + elizaLogger.error( + `Empty response from analysis for ${tokenAddress}` + ); + return []; + } + + elizaLogger.log( + `Analysis result for ${tokenAddress}:`, + response + ); + try { + // Parse the JSON response from the analysis + const result = + typeof response.text === "string" + ? JSON.parse(response.text) + : response.text; + + if (!result) { + elizaLogger.error( + `Invalid analysis result for ${tokenAddress}` + ); + + return []; + } + + if ( + result.shouldTrade && + result.recommendedAction === "BUY" + ) { + await buy({ + result, + runtime, + state, + tokenAddress, + tokenData, + twitterService, + trustScore, + }); + } else if (result.recommendedAction === "SELL") { + await sell({ + latestTrade, + result, + runtime, + state, + tokenAddress, + tokenProvider, + trustScoreDb, + twitterService, + trustScore, + }); + } else { + elizaLogger.log( + `Trade not recommended for ${tokenAddress}:`, + result + ); + } + } catch (parseError) {} + return []; + } + ); + cacheEntry.analysisResult = analysisResult; + tokenCache.set(tokenAddress, cacheEntry); + } catch (tokenError) { + elizaLogger.error(`Error processing token ${tokenAddress}:`, { + error: tokenError, + stack: tokenError instanceof Error ? tokenError.stack : undefined, + }); + await new Promise((resolve) => setTimeout(resolve, 2000)); + } } async function buy({ - runtime, - tokenAddress, - state, - tokenData, - result, - twitterService, - trustScore, + runtime, + tokenAddress, + state, + tokenData, + result, + twitterService, + trustScore, }: { - runtime: IAgentRuntime; - tokenAddress: string; - state: State; - tokenData: ProcessedTokenData; - result: any; - twitterService: TwitterService; - trustScore: number; + runtime: IAgentRuntime; + tokenAddress: string; + state: State; + tokenData: ProcessedTokenData; + result: any; + twitterService: TwitterService; + trustScore: number; }) { - elizaLogger.log(`Trade recommended for ${tokenAddress}:`, result); + elizaLogger.log(`Trade recommended for ${tokenAddress}:`, result); - // Continue with simulation if analysis recommends trading - const simulationService = new SimulationService(); - const simulation = await simulationService.simulateTrade( - tokenAddress, - result.suggestedAmount || SAFETY_LIMITS.MINIMUM_TRADE - ); + // Continue with simulation if analysis recommends trading + const simulationService = new SimulationService(); + const simulation = await simulationService.simulateTrade( + tokenAddress, + result.suggestedAmount || SAFETY_LIMITS.MINIMUM_TRADE + ); - if (simulation.recommendedAction === "EXECUTE") { - try { - // Check wallet balance before trade - const currentBalance = await getWalletBalance(runtime); + if (simulation.recommendedAction === "EXECUTE") { + try { + // Check wallet balance before trade + const currentBalance = await getWalletBalance(runtime); - const tradeAmount = Math.min( - result.suggestedAmount || SAFETY_LIMITS.MINIMUM_TRADE, - currentBalance * 0.95 // Leave some SOL for fees - ); + const tradeAmount = Math.min( + result.suggestedAmount || SAFETY_LIMITS.MINIMUM_TRADE, + currentBalance * 0.95 // Leave some SOL for fees + ); - if (tradeAmount < SAFETY_LIMITS.MINIMUM_TRADE) { - elizaLogger.warn( - `Insufficient balance for trade: ${currentBalance} SOL` + if (tradeAmount < SAFETY_LIMITS.MINIMUM_TRADE) { + elizaLogger.warn( + `Insufficient balance for trade: ${currentBalance} SOL` + ); + } + + // Create trade memory object + const tradeMemory: Memory = { + userId: state.userId, + agentId: runtime.agentId, + roomId: state.roomId, + content: { + text: `Execute trade for ${tokenAddress}`, + tokenAddress, + amount: SAFETY_LIMITS.MINIMUM_TRADE, + action: "BUY", + source: "system", + type: "trade", + }, + }; + + // Execute trade using our custom function + const tradeResult = await executeTrade(runtime, { + tokenAddress, + amount: tradeAmount, + slippage: tokenAddress.startsWith("0x") ? 0.03 : 0.3, // 3% for Base, 30% for Solana + chain: tokenAddress.startsWith("0x") ? "base" : "solana", + }); + + if (tradeResult.success) { + elizaLogger.log( + `Trade executed successfully for ${tokenAddress}:`, + { + signature: tradeResult.signature, + amount: tradeAmount, + memory: tradeMemory, + } + ); + + // Check rate limit before tweeting + if (twitterService && result.recommendedAction === "BUY") { + await tweetTrade(twitterService, { + token: + tokenData.dexScreenerData.pairs[0]?.baseToken + ?.symbol || tokenAddress, + tokenAddress: tokenAddress, + amount: tradeAmount, + trustScore: Number(trustScore) || 0, + riskLevel: result.riskLevel || "MEDIUM", + marketData: { + priceChange24h: + tokenData.dexScreenerData.pairs[0]?.priceChange + ?.h24 || 0, + volume24h: + tokenData.dexScreenerData.pairs[0]?.volume + ?.h24 || 0, + liquidity: { + usd: + tokenData.dexScreenerData.pairs[0] + ?.liquidity?.usd || 0, + }, + }, + timestamp: Date.now(), + signature: tradeResult.signature, + hash: tradeResult.hash, + action: "BUY", + price: Number( + tokenData.dexScreenerData.pairs[0]?.priceUsd || 0 + ), + }); + } else { + elizaLogger.log("Skipping tweet due to rate limit"); + } + + // Record trade using TrustScoreDatabase methods + const trustScoreDb = new TrustScoreDatabase( + runtime.databaseAdapter.db + ); + + try { + // Remove the PublicKey validation for Base addresses + elizaLogger.log( + `Attempting to validate token address: ${tokenAddress}` + ); + const formattedAddress = tokenAddress.startsWith("0x") + ? tokenAddress + : new PublicKey(tokenAddress).toBase58(); // Only convert Solana addresses + elizaLogger.log( + `Token address validated successfully: ${formattedAddress}` + ); + + // Create a new recommender ID for this trade + const uuid = uuidv4(); + const recommender = + await trustScoreDb.getOrCreateRecommender({ + id: uuid, + address: "", + solanaPubkey: + runtime.getSetting("WALLET_PUBLIC_KEY") || "", + }); + elizaLogger.log(`Created/retrieved recommender:`, { + recommender, + chainType: tokenAddress.startsWith("0x") + ? "base" + : "solana", + }); + + // Prepare trade data + const tradeData = { + buy_amount: tradeAmount, + is_simulation: false, + token_address: new PublicKey(tokenAddress).toBase58(), + buy_price: + tokenData.dexScreenerData.pairs[0]?.priceUsd || 0, + buy_timeStamp: new Date().toISOString(), + buy_market_cap: + tokenData.dexScreenerData.pairs[0]?.marketCap || 0, + buy_liquidity: + tokenData.dexScreenerData.pairs[0]?.liquidity + ?.usd || 0, + buy_value_usd: + tradeAmount * + Number( + tokenData.dexScreenerData.pairs[0]?.priceUsd || + 0 + ), + }; + elizaLogger.log(`Prepared trade data:`, tradeData); + + // Create trade record directly using trustScoreDb + await trustScoreDb.addTradePerformance( + { + token_address: formattedAddress, // Use the properly formatted address + recommender_id: recommender.id, + buy_price: Number(tradeData.buy_price), + buy_timeStamp: tradeData.buy_timeStamp, + buy_amount: tradeData.buy_amount, + buy_value_usd: tradeData.buy_value_usd, + buy_market_cap: tradeData.buy_market_cap, + buy_liquidity: tradeData.buy_liquidity, + buy_sol: tradeAmount, + last_updated: new Date().toISOString(), + sell_price: 0, + sell_timeStamp: "", + sell_amount: 0, + received_sol: 0, + sell_value_usd: 0, + sell_market_cap: 0, + sell_liquidity: 0, + profit_usd: 0, + profit_percent: 0, + market_cap_change: 0, + liquidity_change: 0, + rapidDump: false, + }, + false + ); + + elizaLogger.log( + `Successfully recorded trade performance for ${tokenAddress}` + ); + } catch (error) { + elizaLogger.error("Failed to record trade performance:", { + error, + tokenAddress, + errorMessage: + error instanceof Error + ? error.message + : String(error), + stack: error instanceof Error ? error.stack : undefined, + errorType: error?.constructor?.name, + }); + } + } else { + elizaLogger.error( + `Trade execution failed for ${tokenAddress}:`, + tradeResult.error + ); + } + } catch (tradeError) { + elizaLogger.error( + `Error during trade execution for ${tokenAddress}:`, + { + error: tradeError, + stack: + tradeError instanceof Error + ? tradeError.stack + : undefined, + } + ); + } + } else { + elizaLogger.log( + `Simulation rejected trade for ${tokenAddress}:`, + simulation ); - } + } +} + +async function sell({ + state, + runtime, + tokenAddress, + tokenProvider, + twitterService, + trustScoreDb, + latestTrade, + result, + trustScore, +}: { + state: State; + runtime: IAgentRuntime; + tokenAddress: string; + tokenProvider: TokenProvider; + twitterService: TwitterService; + trustScoreDb: TrustScoreDatabase; + result: any; + latestTrade: TradePerformance; + trustScore: number; +}) { + // Get the trade amount from the latest trade + const tradeAmount = Number(latestTrade?.buy_amount || 0); - // Create trade memory object - const tradeMemory: Memory = { + // Create and save trade memory object for sell + const tradeMemory: Memory = { userId: state.userId, agentId: runtime.agentId, roomId: state.roomId, content: { - text: `Execute trade for ${tokenAddress}`, - tokenAddress, - amount: SAFETY_LIMITS.MINIMUM_TRADE, - action: "BUY", - source: "system", - type: "trade", + text: `Execute sell for ${tokenAddress}`, + tokenAddress, + amount: tradeAmount, + action: "SELL", + source: "system", + type: "trade", }, - }; + }; - // Execute trade using our custom function - const tradeResult = await executeTrade(runtime, { + // Execute sell trade + const tradeResult = await executeTrade(runtime, { tokenAddress, amount: tradeAmount, - slippage: tokenAddress.startsWith("0x") ? 0.03 : 0.3, // 3% for Base, 30% for Solana - chain: tokenAddress.startsWith("0x") ? "base" : "solana", - }); - - if (tradeResult.success) { - elizaLogger.log(`Trade executed successfully for ${tokenAddress}:`, { - signature: tradeResult.signature, - amount: tradeAmount, - memory: tradeMemory, - }); + slippage: 0.3, // 30% for Solana + chain: "solana", + }); - // Check rate limit before tweeting - if (twitterService && result.recommendedAction === "BUY") { - await tweetTrade(twitterService, { - token: - tokenData.dexScreenerData.pairs[0]?.baseToken?.symbol || - tokenAddress, - tokenAddress: tokenAddress, - amount: tradeAmount, - trustScore: Number(trustScore) || 0, - riskLevel: result.riskLevel || "MEDIUM", - marketData: { - priceChange24h: - tokenData.dexScreenerData.pairs[0]?.priceChange?.h24 || 0, - volume24h: tokenData.dexScreenerData.pairs[0]?.volume?.h24 || 0, - liquidity: { - usd: tokenData.dexScreenerData.pairs[0]?.liquidity?.usd || 0, - }, - }, - timestamp: Date.now(), + if (tradeResult.success) { + elizaLogger.log(`Sell executed successfully for ${tokenAddress}:`, { signature: tradeResult.signature, - hash: tradeResult.hash, - action: "BUY", - price: Number(tokenData.dexScreenerData.pairs[0]?.priceUsd || 0), - }); - } else { - elizaLogger.log("Skipping tweet due to rate limit"); - } + amount: tradeAmount, + }); - // Record trade using TrustScoreDatabase methods - const trustScoreDb = new TrustScoreDatabase(runtime.databaseAdapter.db); + // Get token data first + const tokenData = await tokenProvider.getProcessedTokenData(); - try { - // Remove the PublicKey validation for Base addresses - elizaLogger.log( - `Attempting to validate token address: ${tokenAddress}` - ); - const formattedAddress = tokenAddress.startsWith("0x") - ? tokenAddress - : new PublicKey(tokenAddress).toBase58(); // Only convert Solana addresses - elizaLogger.log( - `Token address validated successfully: ${formattedAddress}` - ); - - // Create a new recommender ID for this trade - const uuid = uuidv4(); - const recommender = await trustScoreDb.getOrCreateRecommender({ + // Create recommender + const uuid = uuidv4(); + const recommender = await trustScoreDb.getOrCreateRecommender({ id: uuid, - address: "", + address: "", // Empty since we're only handling Solana solanaPubkey: runtime.getSetting("WALLET_PUBLIC_KEY") || "", - }); - elizaLogger.log(`Created/retrieved recommender:`, { - recommender, - chainType: tokenAddress.startsWith("0x") ? "base" : "solana", - }); - - // Prepare trade data - const tradeData = { - buy_amount: tradeAmount, - is_simulation: false, - token_address: new PublicKey(tokenAddress).toBase58(), - buy_price: tokenData.dexScreenerData.pairs[0]?.priceUsd || 0, - buy_timeStamp: new Date().toISOString(), - buy_market_cap: tokenData.dexScreenerData.pairs[0]?.marketCap || 0, - buy_liquidity: - tokenData.dexScreenerData.pairs[0]?.liquidity?.usd || 0, - buy_value_usd: - tradeAmount * - Number(tokenData.dexScreenerData.pairs[0]?.priceUsd || 0), - }; - elizaLogger.log(`Prepared trade data:`, tradeData); - - // Create trade record directly using trustScoreDb - await trustScoreDb.addTradePerformance( - { - token_address: formattedAddress, // Use the properly formatted address - recommender_id: recommender.id, - buy_price: Number(tradeData.buy_price), - buy_timeStamp: tradeData.buy_timeStamp, - buy_amount: tradeData.buy_amount, - buy_value_usd: tradeData.buy_value_usd, - buy_market_cap: tradeData.buy_market_cap, - buy_liquidity: tradeData.buy_liquidity, - buy_sol: tradeAmount, - last_updated: new Date().toISOString(), - sell_price: 0, - sell_timeStamp: "", - sell_amount: 0, - received_sol: 0, - sell_value_usd: 0, - sell_market_cap: 0, - sell_liquidity: 0, - profit_usd: 0, - profit_percent: 0, - market_cap_change: 0, - liquidity_change: 0, - rapidDump: false, - }, - false - ); - - elizaLogger.log( - `Successfully recorded trade performance for ${tokenAddress}` - ); - } catch (error) { - elizaLogger.error("Failed to record trade performance:", { - error, + }); + + // Update sell details and get prices + const { sellDetails, currentPrice } = await updateSellDetails( + runtime, tokenAddress, - errorMessage: - error instanceof Error ? error.message : String(error), - stack: error instanceof Error ? error.stack : undefined, - errorType: error?.constructor?.name, - }); - } - } else { - elizaLogger.error( - `Trade execution failed for ${tokenAddress}:`, - tradeResult.error + recommender.id, + tradeAmount, + latestTrade, + tokenData ); - } - } catch (tradeError) { - elizaLogger.error(`Error during trade execution for ${tokenAddress}:`, { - error: tradeError, - stack: tradeError instanceof Error ? tradeError.stack : undefined, - }); - } - } else { - elizaLogger.log( - `Simulation rejected trade for ${tokenAddress}:`, - simulation - ); - } -} - -async function sell({ - state, - runtime, - tokenAddress, - tokenProvider, - twitterService, - trustScoreDb, - latestTrade, - result, - trustScore, -}: { - state: State; - runtime: IAgentRuntime; - tokenAddress: string; - tokenProvider: TokenProvider; - twitterService: TwitterService; - trustScoreDb: TrustScoreDatabase; - result: any; - latestTrade: TradePerformance; - trustScore: number; -}) { - // Get the trade amount from the latest trade - const tradeAmount = Number(latestTrade?.buy_amount || 0); - - // Create and save trade memory object for sell - const tradeMemory: Memory = { - userId: state.userId, - agentId: runtime.agentId, - roomId: state.roomId, - content: { - text: `Execute sell for ${tokenAddress}`, - tokenAddress, - amount: tradeAmount, - action: "SELL", - source: "system", - type: "trade", - }, - }; - - // Execute sell trade - const tradeResult = await executeTrade(runtime, { - tokenAddress, - amount: tradeAmount, - slippage: 0.3, // 30% for Solana - chain: "solana", - }); - - if (tradeResult.success) { - elizaLogger.log(`Sell executed successfully for ${tokenAddress}:`, { - signature: tradeResult.signature, - amount: tradeAmount, - }); - - // Get token data first - const tokenData = await tokenProvider.getProcessedTokenData(); - - // Create recommender - const uuid = uuidv4(); - const recommender = await trustScoreDb.getOrCreateRecommender({ - id: uuid, - address: "", // Empty since we're only handling Solana - solanaPubkey: runtime.getSetting("WALLET_PUBLIC_KEY") || "", - }); - // Update sell details and get prices - const { sellDetails, currentPrice } = await updateSellDetails( - runtime, - tokenAddress, - recommender.id, - tradeAmount, - latestTrade, - tokenData - ); + // Post tweet if enabled + if (twitterService) { + await tweetTrade(twitterService, { + token: + tokenData.dexScreenerData.pairs[0]?.baseToken?.symbol || + tokenAddress, + tokenAddress: tokenAddress, + amount: tradeAmount, + trustScore: Number(trustScore) || 0, + riskLevel: result.riskLevel || "MEDIUM", + marketData: { + priceChange24h: + tokenData.dexScreenerData.pairs[0]?.priceChange?.h24 || + 0, + volume24h: + tokenData.dexScreenerData.pairs[0]?.volume?.h24 || 0, + liquidity: { + usd: + tokenData.dexScreenerData.pairs[0]?.liquidity + ?.usd || 0, + }, + }, + timestamp: Date.now(), + signature: tradeResult.signature, + hash: tradeResult.hash, + action: "SELL", + price: Number(currentPrice), + profitPercent: `${sellDetails.profit_percent.toFixed(2)}%`, + profitUsd: `${sellDetails.profit_usd.toFixed(4)} USD`, + reason: `P/L: ${sellDetails.profit_percent.toFixed(2)}%`, + }); + } - // Post tweet if enabled - if (twitterService) { - await tweetTrade(twitterService, { - token: - tokenData.dexScreenerData.pairs[0]?.baseToken?.symbol || tokenAddress, - tokenAddress: tokenAddress, - amount: tradeAmount, - trustScore: Number(trustScore) || 0, - riskLevel: result.riskLevel || "MEDIUM", - marketData: { - priceChange24h: - tokenData.dexScreenerData.pairs[0]?.priceChange?.h24 || 0, - volume24h: tokenData.dexScreenerData.pairs[0]?.volume?.h24 || 0, - liquidity: { - usd: tokenData.dexScreenerData.pairs[0]?.liquidity?.usd || 0, - }, - }, - timestamp: Date.now(), - signature: tradeResult.signature, - hash: tradeResult.hash, - action: "SELL", - price: Number(currentPrice), - profitPercent: `${sellDetails.profit_percent.toFixed(2)}%`, - profitUsd: `${sellDetails.profit_usd.toFixed(4)} USD`, - reason: `P/L: ${sellDetails.profit_percent.toFixed(2)}%`, - }); + elizaLogger.log( + `Successfully updated sell details for ${tokenAddress}`, + { + sellPrice: currentPrice, + sellAmount: tradeAmount, + } + ); + } else { + elizaLogger.error( + `Sell execution failed for ${tokenAddress}:`, + tradeResult.error + ); } - - elizaLogger.log(`Successfully updated sell details for ${tokenAddress}`, { - sellPrice: currentPrice, - sellAmount: tradeAmount, - }); - } else { - elizaLogger.error( - `Sell execution failed for ${tokenAddress}:`, - tradeResult.error - ); - } } export default createRabbiTraderPlugin; diff --git a/packages/plugin-rabbi-trader/src/services/simulationService.ts b/packages/plugin-rabbi-trader/src/services/simulationService.ts index cf23a1c7e42..867b488c3c8 100644 --- a/packages/plugin-rabbi-trader/src/services/simulationService.ts +++ b/packages/plugin-rabbi-trader/src/services/simulationService.ts @@ -1,4 +1,4 @@ -import { elizaLogger } from "@ai16z/eliza"; +import { elizaLogger } from "@elizaos/core"; import { TokenProvider } from "../providers/token"; import { TrustScoreProvider } from "../providers/trustScoreProvider"; @@ -9,19 +9,24 @@ export class SimulationService { this.trustScoreProvider = new TrustScoreProvider(); } - async simulateTrade(tokenAddress: string, amount: number): Promise<{ + async simulateTrade( + tokenAddress: string, + amount: number + ): Promise<{ expectedPrice: number; priceImpact: number; recommendedAction: "EXECUTE" | "ABORT"; reason: string; }> { try { - const evaluation = await this.trustScoreProvider.evaluateToken(tokenAddress); + const evaluation = + await this.trustScoreProvider.evaluateToken(tokenAddress); const tokenProvider = new TokenProvider(tokenAddress); const tokenData = await tokenProvider.getProcessedTokenData(); // Get liquidity from DexScreener data - const liquidity = tokenData.dexScreenerData.pairs[0]?.liquidity?.usd || 0; + const liquidity = + tokenData.dexScreenerData.pairs[0]?.liquidity?.usd || 0; const priceImpact = (amount / liquidity) * 100; let recommendedAction: "EXECUTE" | "ABORT" = "ABORT"; @@ -36,7 +41,7 @@ export class SimulationService { expectedPrice: tokenData.tradeData.price, priceImpact, recommendedAction, - reason + reason, }; } catch (error) { elizaLogger.error("Trade simulation failed:", error); diff --git a/packages/plugin-rabbi-trader/src/tokenUtils.ts b/packages/plugin-rabbi-trader/src/tokenUtils.ts index 703d6c4caf9..0e84ddac6fd 100644 --- a/packages/plugin-rabbi-trader/src/tokenUtils.ts +++ b/packages/plugin-rabbi-trader/src/tokenUtils.ts @@ -1,19 +1,19 @@ import * as fs from "fs"; import * as path from "path"; -import { elizaLogger } from "@elizaOS/core"; +import { elizaLogger } from "@elizaos/core"; export function loadTokenAddresses(): string[] { - try { - const filePath = path.resolve( - process.cwd(), - "../characters/tokens/tokenaddresses.json", - ); - const data = fs.readFileSync(filePath, "utf8"); - const addresses = JSON.parse(data); - elizaLogger.log("Loaded token addresses:", addresses); - return addresses; - } catch (error) { - elizaLogger.error("Failed to load token addresses:", error); - throw new Error("Token addresses file not found or invalid"); - } + try { + const filePath = path.resolve( + process.cwd(), + "../characters/tokens/tokenaddresses.json" + ); + const data = fs.readFileSync(filePath, "utf8"); + const addresses = JSON.parse(data); + elizaLogger.log("Loaded token addresses:", addresses); + return addresses; + } catch (error) { + elizaLogger.error("Failed to load token addresses:", error); + throw new Error("Token addresses file not found or invalid"); + } } diff --git a/packages/plugin-rabbi-trader/src/utils.ts b/packages/plugin-rabbi-trader/src/utils.ts index da1c2126a9a..50d56c58094 100644 --- a/packages/plugin-rabbi-trader/src/utils.ts +++ b/packages/plugin-rabbi-trader/src/utils.ts @@ -1,168 +1,168 @@ -import { elizaLogger, IAgentRuntime, settings, State } from "@ai16z/eliza"; +import { elizaLogger, IAgentRuntime, settings, State } from "@elizaos/core"; import { PublicKey } from "@solana/web3.js"; import { PROVIDER_CONFIG } from "./config"; -import { - ANALYSIS_HISTORY_EXPIRY, -} from "./constants"; +import { ANALYSIS_HISTORY_EXPIRY } from "./constants"; export function isValidSolanaAddress(address: string): boolean { - try { - - // Check if it's a valid Solana public key format - new PublicKey(address); - return true; - } catch { - return false; - } + try { + // Check if it's a valid Solana public key format + new PublicKey(address); + return true; + } catch { + return false; + } } export async function fetchWithRetry( - url: string, - options: RequestInit = {}, - chain: "solana" | "base" = "solana", + url: string, + options: RequestInit = {}, + chain: "solana" | "base" = "solana" ): Promise { - let lastError: Error; - - for (let i = 0; i < PROVIDER_CONFIG.MAX_RETRIES; i++) { - try { - elizaLogger.log(`Attempt ${i + 1} for ${url} with chain ${chain}`); - - // Ensure headers are properly initialized - const headers = { - Accept: "application/json", - "x-chain": chain, - "X-API-KEY": settings.BIRDEYE_API_KEY || "", - ...options.headers, - }; - + let lastError: Error; + + for (let i = 0; i < PROVIDER_CONFIG.MAX_RETRIES; i++) { + try { + elizaLogger.log(`Attempt ${i + 1} for ${url} with chain ${chain}`); + + // Ensure headers are properly initialized + const headers = { + Accept: "application/json", + "x-chain": chain, + "X-API-KEY": settings.BIRDEYE_API_KEY || "", + ...options.headers, + }; + + const response = await fetch(url, { + ...options, + headers, + }); + + const responseText = await response.text(); + + if (!response.ok) { + throw new Error( + `HTTP error! status: ${response.status}, message: ${responseText}` + ); + } + + try { + return JSON.parse(responseText); + } catch (parseError) { + throw new Error( + `Failed to parse response: ${responseText}, error: ${parseError.message}` + ); + } + } catch (error) { + elizaLogger.error(`Attempt ${i + 1} failed:`, { + error: error instanceof Error ? error.message : String(error), + url, + chain, + attempt: i + 1, + }); + lastError = + error instanceof Error ? error : new Error(String(error)); + + if (i < PROVIDER_CONFIG.MAX_RETRIES - 1) { + await new Promise((resolve) => + setTimeout( + resolve, + PROVIDER_CONFIG.RETRY_DELAY * Math.pow(2, i) + ) + ); + continue; + } + } + } - const response = await fetch(url, { - ...options, - headers, - }); + throw lastError; +} - const responseText = await response.text(); +export function decodeBase58(str: string): Uint8Array { + const ALPHABET = + "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; + const ALPHABET_MAP = new Map( + ALPHABET.split("").map((c, i) => [c, BigInt(i)]) + ); - if (!response.ok) { - throw new Error( - `HTTP error! status: ${response.status}, message: ${responseText}`, - ); - } + let result = BigInt(0); + for (const char of str) { + const value = ALPHABET_MAP.get(char); + if (value === undefined) throw new Error("Invalid base58 character"); + result = result * BigInt(58) + value; + } - try { - return JSON.parse(responseText); - } catch (parseError) { - throw new Error( - `Failed to parse response: ${responseText}, error: ${parseError.message}`, - ); - } - } catch (error) { - elizaLogger.error(`Attempt ${i + 1} failed:`, { - error: error instanceof Error ? error.message : String(error), - url, - chain, - attempt: i + 1, - }); - lastError = error instanceof Error ? error : new Error(String(error)); - - if (i < PROVIDER_CONFIG.MAX_RETRIES - 1) { - await new Promise((resolve) => - setTimeout(resolve, PROVIDER_CONFIG.RETRY_DELAY * Math.pow(2, i)), - ); - continue; - } + const bytes = []; + while (result > 0n) { + bytes.unshift(Number(result & 0xffn)); + result = result >> 8n; } - } - throw lastError; -} + for (let i = 0; i < str.length && str[i] === "1"; i++) { + bytes.unshift(0); + } -export function decodeBase58(str: string): Uint8Array { - const ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; - const ALPHABET_MAP = new Map( - ALPHABET.split("").map((c, i) => [c, BigInt(i)]), - ); - - let result = BigInt(0); - for (const char of str) { - const value = ALPHABET_MAP.get(char); - if (value === undefined) throw new Error("Invalid base58 character"); - result = result * BigInt(58) + value; - } - - const bytes = []; - while (result > 0n) { - bytes.unshift(Number(result & 0xffn)); - result = result >> 8n; - } - - for (let i = 0; i < str.length && str[i] === "1"; i++) { - bytes.unshift(0); - } - - return new Uint8Array(bytes); + return new Uint8Array(bytes); } - interface AnalyzedToken { - address: string; - timestamp: number; - symbol: string; + address: string; + timestamp: number; + symbol: string; } export async function manageAnalyzedTokens( - runtime: IAgentRuntime, - state: any, - newToken?: AnalyzedToken, + runtime: IAgentRuntime, + state: any, + newToken?: AnalyzedToken ): Promise { - try { - const historyKey = "analyzed_tokens_history"; - let history: AnalyzedToken[] = []; + try { + const historyKey = "analyzed_tokens_history"; + let history: AnalyzedToken[] = []; - if (!state) { - state = {}; - } + if (!state) { + state = {}; + } - if (state[historyKey]) { - try { - const parsed = JSON.parse(state[historyKey]); - if (Array.isArray(parsed)) { - history = parsed; + if (state[historyKey]) { + try { + const parsed = JSON.parse(state[historyKey]); + if (Array.isArray(parsed)) { + history = parsed; + } + } catch (e) { + elizaLogger.warn("Failed to parse history, resetting", e); + } } - } catch (e) { - elizaLogger.warn("Failed to parse history, resetting", e); - } - } - const now = Date.now(); - history = history.filter( - (token) => - token && - token.timestamp && - now - token.timestamp < ANALYSIS_HISTORY_EXPIRY, - ); + const now = Date.now(); + history = history.filter( + (token) => + token && + token.timestamp && + now - token.timestamp < ANALYSIS_HISTORY_EXPIRY + ); - if (newToken) { - history.push(newToken); - } + if (newToken) { + history.push(newToken); + } - // Update state with roomId - state = await runtime.updateRecentMessageState({ - ...state, - userId: runtime.agentId, - agentId: runtime.agentId, - roomId: runtime.agentId, - content: { - ...state.content, - [historyKey]: JSON.stringify(history), - }, - } as State); - - return history; - } catch (error) { - elizaLogger.error("Failed to manage analyzed tokens history:", { - error: error instanceof Error ? error.message : error, - }); - return []; - } + // Update state with roomId + state = await runtime.updateRecentMessageState({ + ...state, + userId: runtime.agentId, + agentId: runtime.agentId, + roomId: runtime.agentId, + content: { + ...state.content, + [historyKey]: JSON.stringify(history), + }, + } as State); + + return history; + } catch (error) { + elizaLogger.error("Failed to manage analyzed tokens history:", { + error: error instanceof Error ? error.message : error, + }); + return []; + } } diff --git a/packages/plugin-rabbi-trader/src/wallet.ts b/packages/plugin-rabbi-trader/src/wallet.ts index 9235e8ff0ef..326d6b1b7b9 100644 --- a/packages/plugin-rabbi-trader/src/wallet.ts +++ b/packages/plugin-rabbi-trader/src/wallet.ts @@ -1,12 +1,7 @@ -import { elizaLogger, IAgentRuntime } from "@elizaOS/core"; -import { - Connection, - Keypair, - VersionedTransaction, -} from "@solana/web3.js"; +import { elizaLogger, IAgentRuntime } from "@elizaos/core"; +import { Connection, Keypair, VersionedTransaction } from "@solana/web3.js"; import { decodeBase58 } from "./utils"; -import { SAFETY_LIMITS } from "./constants"; - +import { SAFETY_LIMITS } from "./constants"; /** * Gets wallet keypair from runtime settings @@ -15,20 +10,20 @@ import { SAFETY_LIMITS } from "./constants"; * @throws Error if private key is missing or invalid */ export function getWalletKeypair(runtime?: IAgentRuntime): Keypair { - // Check chain type from token address or configuration - - const privateKeyString = runtime?.getSetting("WALLET_PRIVATE_KEY"); - if (!privateKeyString) { - throw new Error("No wallet private key configured"); - } - - try { - const privateKeyBytes = decodeBase58(privateKeyString); - return Keypair.fromSecretKey(privateKeyBytes); - } catch (error) { - elizaLogger.error("Failed to create wallet keypair:", error); - throw error; - } + // Check chain type from token address or configuration + + const privateKeyString = runtime?.getSetting("WALLET_PRIVATE_KEY"); + if (!privateKeyString) { + throw new Error("No wallet private key configured"); + } + + try { + const privateKeyBytes = decodeBase58(privateKeyString); + return Keypair.fromSecretKey(privateKeyBytes); + } catch (error) { + elizaLogger.error("Failed to create wallet keypair:", error); + throw error; + } } /** @@ -37,243 +32,245 @@ export function getWalletKeypair(runtime?: IAgentRuntime): Keypair { * @returns Balance in SOL */ export async function getWalletBalance( - runtime: IAgentRuntime, + runtime: IAgentRuntime ): Promise { - try { - - // Existing Solana balance logic - const walletKeypair = getWalletKeypair(runtime); - const walletPubKey = walletKeypair.publicKey; - const connection = new Connection( - runtime.getSetting("RPC_URL") || "https://api.mainnet-beta.solana.com", - ); - - const balance = await connection.getBalance(walletPubKey); - const solBalance = balance / 1e9; - - elizaLogger.log("Fetched Solana wallet balance:", { - address: walletPubKey.toBase58(), - lamports: balance, - sol: solBalance, - }); - - return solBalance; - } catch (error) { - elizaLogger.error("Failed to get wallet balance:", error); - return 0; - } + try { + // Existing Solana balance logic + const walletKeypair = getWalletKeypair(runtime); + const walletPubKey = walletKeypair.publicKey; + const connection = new Connection( + runtime.getSetting("RPC_URL") || + "https://api.mainnet-beta.solana.com" + ); + + const balance = await connection.getBalance(walletPubKey); + const solBalance = balance / 1e9; + + elizaLogger.log("Fetched Solana wallet balance:", { + address: walletPubKey.toBase58(), + lamports: balance, + sol: solBalance, + }); + + return solBalance; + } catch (error) { + elizaLogger.error("Failed to get wallet balance:", error); + return 0; + } } // Add helper function to get connection async function getConnection(runtime: IAgentRuntime): Promise { - return new Connection( - runtime.getSetting("RPC_URL") || "https://api.mainnet-beta.solana.com", - ); + return new Connection( + runtime.getSetting("RPC_URL") || "https://api.mainnet-beta.solana.com" + ); } // Add executeTrade function export async function executeTrade( - runtime: IAgentRuntime, - params: { - tokenAddress: string; - amount: number; - slippage: number; - isSell?: boolean; - chain?: "base" | "solana"; - }, - retryCount = 0, + runtime: IAgentRuntime, + params: { + tokenAddress: string; + amount: number; + slippage: number; + isSell?: boolean; + chain?: "base" | "solana"; + }, + retryCount = 0 ): Promise { - - // Existing Solana trade logic remains unchanged - try { - elizaLogger.log("Executing Solana trade with params:", params); - - const SOL_ADDRESS = "So11111111111111111111111111111111111111112"; - - if (!params.isSell && params.amount < SAFETY_LIMITS.MINIMUM_TRADE) { - elizaLogger.warn("Trade amount too small:", { - amount: params.amount, - minimumRequired: SAFETY_LIMITS.MINIMUM_TRADE, - }); - return { - success: false, - error: "Trade amount too small", - details: { - amount: params.amount, - minimumRequired: SAFETY_LIMITS.MINIMUM_TRADE, - }, - }; + // Existing Solana trade logic remains unchanged + try { + elizaLogger.log("Executing Solana trade with params:", params); + + const SOL_ADDRESS = "So11111111111111111111111111111111111111112"; + + if (!params.isSell && params.amount < SAFETY_LIMITS.MINIMUM_TRADE) { + elizaLogger.warn("Trade amount too small:", { + amount: params.amount, + minimumRequired: SAFETY_LIMITS.MINIMUM_TRADE, + }); + return { + success: false, + error: "Trade amount too small", + details: { + amount: params.amount, + minimumRequired: SAFETY_LIMITS.MINIMUM_TRADE, + }, + }; + } + + const walletKeypair = getWalletKeypair(runtime); + const connection = await getConnection(runtime); + + // Setup swap parameters + const inputTokenCA = params.isSell ? params.tokenAddress : SOL_ADDRESS; + const outputTokenCA = params.isSell ? SOL_ADDRESS : params.tokenAddress; + const swapAmount = Math.floor(params.amount * 1e9); + + elizaLogger.log("Trade execution details:", { + isSell: params.isSell, + inputToken: inputTokenCA, + outputToken: outputTokenCA, + amount: params.amount, + slippage: params.slippage, + }); + + // Get quote + const quoteResponse = await fetch( + `https://quote-api.jup.ag/v6/quote?inputMint=${inputTokenCA}&outputMint=${outputTokenCA}&amount=${swapAmount}&slippageBps=${Math.floor(params.slippage * 10000)}` + ); + + if (!quoteResponse.ok) { + const error = await quoteResponse.text(); + elizaLogger.warn("Quote request failed:", { + status: quoteResponse.status, + error, + }); + return { + success: false, + error: "Failed to get quote", + details: { status: quoteResponse.status, error }, + }; + } + + const quoteData = await quoteResponse.json(); + if (!quoteData || quoteData.error) { + elizaLogger.warn("Invalid quote data:", quoteData); + return { + success: false, + error: "Invalid quote data", + details: quoteData, + }; + } + + elizaLogger.log("Quote received:", quoteData); + + // Get swap transaction + const swapResponse = await fetch("https://quote-api.jup.ag/v6/swap", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + quoteResponse: quoteData, + userPublicKey: walletKeypair.publicKey.toString(), + wrapAndUnwrapSol: true, + computeUnitPriceMicroLamports: 2000000, + dynamicComputeUnitLimit: true, + }), + }); + + const swapData = await swapResponse.json(); + if (!swapData?.swapTransaction) { + throw new Error("No swap transaction returned"); + } + + elizaLogger.log("Swap transaction received"); + + // Deserialize transaction + const transactionBuf = Buffer.from(swapData.swapTransaction, "base64"); + const tx = VersionedTransaction.deserialize(transactionBuf); + + // Get fresh blockhash and sign transaction + const { blockhash, lastValidBlockHeight } = + await connection.getLatestBlockhash("finalized"); + tx.message.recentBlockhash = blockhash; + tx.sign([walletKeypair]); + + // Send with confirmation using more lenient settings + const signature = await connection.sendTransaction(tx, { + skipPreflight: false, + maxRetries: 5, + preflightCommitment: "processed", + }); + + elizaLogger.log("Transaction sent:", signature); + + // Wait for confirmation with more lenient settings + const confirmation = await connection.confirmTransaction( + { + signature, + blockhash, + lastValidBlockHeight, + }, + "processed" + ); // Use 'processed' instead of default 'finalized' + + if (confirmation.value.err) { + throw new Error(`Transaction failed: ${confirmation.value.err}`); + } + + // Add additional verification + const status = await connection.getSignatureStatus(signature); + if (status.value?.err) { + throw new Error( + `Transaction verification failed: ${status.value.err}` + ); + } + + elizaLogger.log("Solana trade executed successfully:", { + signature, + explorer: `https://solscan.io/tx/${signature}`, + }); + + return { + success: true, + signature, + confirmation, + explorer: `https://solscan.io/tx/${signature}`, + }; + } catch (error) { + // Handle blockhash errors with retry and longer timeout + if ( + (error.message?.includes("Blockhash not found") || + error.message?.includes("block height exceeded")) && + retryCount < 3 + ) { + elizaLogger.warn( + `Transaction error, retrying (${retryCount + 1}/3)...` + ); + await new Promise((resolve) => setTimeout(resolve, 5000)); // Longer delay between retries + return executeTrade(runtime, params, retryCount + 1); + } + + elizaLogger.error("Trade execution failed:", { + error: error instanceof Error ? error.message : error, + stack: error instanceof Error ? error.stack : undefined, + params, + retryCount, + }); + + return { + success: false, + error: error.message || error, + params, + stack: error instanceof Error ? error.stack : undefined, + }; } - - const walletKeypair = getWalletKeypair(runtime); - const connection = await getConnection(runtime); - - // Setup swap parameters - const inputTokenCA = params.isSell ? params.tokenAddress : SOL_ADDRESS; - const outputTokenCA = params.isSell ? SOL_ADDRESS : params.tokenAddress; - const swapAmount = Math.floor(params.amount * 1e9); - - elizaLogger.log("Trade execution details:", { - isSell: params.isSell, - inputToken: inputTokenCA, - outputToken: outputTokenCA, - amount: params.amount, - slippage: params.slippage, - }); - - // Get quote - const quoteResponse = await fetch( - `https://quote-api.jup.ag/v6/quote?inputMint=${inputTokenCA}&outputMint=${outputTokenCA}&amount=${swapAmount}&slippageBps=${Math.floor(params.slippage * 10000)}`, - ); - - if (!quoteResponse.ok) { - const error = await quoteResponse.text(); - elizaLogger.warn("Quote request failed:", { - status: quoteResponse.status, - error, - }); - return { - success: false, - error: "Failed to get quote", - details: { status: quoteResponse.status, error }, - }; - } - - const quoteData = await quoteResponse.json(); - if (!quoteData || quoteData.error) { - elizaLogger.warn("Invalid quote data:", quoteData); - return { - success: false, - error: "Invalid quote data", - details: quoteData, - }; - } - - elizaLogger.log("Quote received:", quoteData); - - // Get swap transaction - const swapResponse = await fetch("https://quote-api.jup.ag/v6/swap", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - quoteResponse: quoteData, - userPublicKey: walletKeypair.publicKey.toString(), - wrapAndUnwrapSol: true, - computeUnitPriceMicroLamports: 2000000, - dynamicComputeUnitLimit: true, - }), - }); - - const swapData = await swapResponse.json(); - if (!swapData?.swapTransaction) { - throw new Error("No swap transaction returned"); - } - - elizaLogger.log("Swap transaction received"); - - // Deserialize transaction - const transactionBuf = Buffer.from(swapData.swapTransaction, "base64"); - const tx = VersionedTransaction.deserialize(transactionBuf); - - // Get fresh blockhash and sign transaction - const { blockhash, lastValidBlockHeight } = - await connection.getLatestBlockhash("finalized"); - tx.message.recentBlockhash = blockhash; - tx.sign([walletKeypair]); - - // Send with confirmation using more lenient settings - const signature = await connection.sendTransaction(tx, { - skipPreflight: false, - maxRetries: 5, - preflightCommitment: "processed", - }); - - elizaLogger.log("Transaction sent:", signature); - - // Wait for confirmation with more lenient settings - const confirmation = await connection.confirmTransaction( - { - signature, - blockhash, - lastValidBlockHeight, - }, - "processed", - ); // Use 'processed' instead of default 'finalized' - - if (confirmation.value.err) { - throw new Error(`Transaction failed: ${confirmation.value.err}`); - } - - // Add additional verification - const status = await connection.getSignatureStatus(signature); - if (status.value?.err) { - throw new Error(`Transaction verification failed: ${status.value.err}`); - } - - elizaLogger.log("Solana trade executed successfully:", { - signature, - explorer: `https://solscan.io/tx/${signature}`, - }); - - return { - success: true, - signature, - confirmation, - explorer: `https://solscan.io/tx/${signature}`, - }; - } catch (error) { - // Handle blockhash errors with retry and longer timeout - if ( - (error.message?.includes("Blockhash not found") || - error.message?.includes("block height exceeded")) && - retryCount < 3 - ) { - elizaLogger.warn(`Transaction error, retrying (${retryCount + 1}/3)...`); - await new Promise((resolve) => setTimeout(resolve, 5000)); // Longer delay between retries - return executeTrade(runtime, params, retryCount + 1); - } - - elizaLogger.error("Trade execution failed:", { - error: error instanceof Error ? error.message : error, - stack: error instanceof Error ? error.stack : undefined, - params, - retryCount, - }); - - return { - success: false, - error: error.message || error, - params, - stack: error instanceof Error ? error.stack : undefined, - }; - } } - export async function getChainWalletBalance( - runtime: IAgentRuntime, - tokenAddress: string, + runtime: IAgentRuntime, + tokenAddress: string ): Promise { - // Get Solana balance + // Get Solana balance return await getWalletBalance(runtime); - } +} // Add this helper function at the top level export async function simulateTransaction( - client: any, - tx: any, + client: any, + tx: any ): Promise { - try { - const result = await client.call({ - account: client.account, - to: tx.to, - data: tx.data, - value: tx.value, - gas: tx.gas, - gasPrice: tx.gasPrice, - }); - return result; - } catch (error) { - return `Simulation failed: ${error.message}`; - } + try { + const result = await client.call({ + account: client.account, + to: tx.to, + data: tx.data, + value: tx.value, + gas: tx.gas, + gasPrice: tx.gasPrice, + }); + return result; + } catch (error) { + return `Simulation failed: ${error.message}`; + } } diff --git a/packages/plugin-solana/src/index.ts b/packages/plugin-solana/src/index.ts index b207ed260ba..ecfe801ef32 100644 --- a/packages/plugin-solana/src/index.ts +++ b/packages/plugin-solana/src/index.ts @@ -15,8 +15,9 @@ import { trustScoreProvider } from "./providers/trustScoreProvider.ts"; import { trustEvaluator } from "./evaluators/trust.ts"; import { TokenProvider } from "./providers/token.ts"; import { WalletProvider } from "./providers/wallet.ts"; +import { getTokenBalance, getTokenBalances } from "./providers/tokenUtils.ts"; -export { TokenProvider, WalletProvider }; +export { TokenProvider, WalletProvider, getTokenBalance, getTokenBalances }; export const solanaPlugin: Plugin = { name: "solana", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 382a8d5df46..b456169188b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1290,7 +1290,7 @@ 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-coinprice: + packages/plugin-coinmarketcap: dependencies: '@elizaos/core': specifier: workspace:* @@ -1306,7 +1306,7 @@ 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: + packages/plugin-coinprice: dependencies: '@elizaos/core': specifier: workspace:* @@ -1320,7 +1320,7 @@ importers: 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) + 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-conflux: dependencies: @@ -2019,6 +2019,57 @@ importers: specifier: ^3.22.4 version: 3.23.8 + packages/plugin-rabbi-trader: + dependencies: + '@elizaos/client-twitter': + specifier: workspace:* + version: link:../client-twitter + '@elizaos/core': + specifier: workspace:* + version: link:../core + '@elizaos/plugin-solana': + specifier: workspace:* + version: link:../plugin-solana + '@elizaos/plugin-trustdb': + specifier: workspace:* + version: link:../plugin-trustdb + '@goat-sdk/core': + specifier: 0.3.8 + version: 0.3.8(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10) + '@goat-sdk/plugin-coingecko': + specifier: 0.1.4 + version: 0.1.4(@goat-sdk/core@0.3.8(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10))(viem@2.21.58(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.23.8)) + '@goat-sdk/plugin-erc20': + specifier: 0.1.7 + version: 0.1.7(@goat-sdk/core@0.3.8(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10))(viem@2.21.58(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.23.8)) + '@goat-sdk/wallet-viem': + specifier: 0.1.3 + version: 0.1.3(@goat-sdk/core@0.3.8(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10))(viem@2.21.58(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.23.8)) + '@solana/web3.js': + specifier: ^1.87.6 + version: 1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) + bignumber: + specifier: 1.1.0 + version: 1.1.0 + bignumber.js: + specifier: 9.1.2 + version: 9.1.2 + node-cache: + specifier: ^5.1.2 + version: 5.1.2 + tsup: + 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) + whatwg-url: + specifier: 7.1.0 + version: 7.1.0 + ws: + specifier: ^8.0.0 + version: 8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + zod: + specifier: 3.23.8 + version: 3.23.8 + packages/plugin-solana: dependencies: '@coral-xyz/anchor': @@ -2488,8 +2539,8 @@ packages: peerDependencies: zod: ^3.0.0 - '@ai-sdk/openai@1.0.14': - resolution: {integrity: sha512-uyOkQNtYsHr4qyV7y0rmMAtdW4LTJoThYo1qXcvQa30RDh/MyvLEOjKYX181Siyp8LcTqYvwf6Tt+eckdVTTug==} + '@ai-sdk/openai@1.0.15': + resolution: {integrity: sha512-acX2crxBrkyfIlTtJGGX/YD/ck6L+LpPdaYQqGiahacHX07yn1nUE1jlnNLmTnDFoMwgxJXXt/wI16LC3ybYZg==} engines: {node: '>=18'} peerDependencies: zod: ^3.0.0 @@ -5446,9 +5497,26 @@ packages: '@goat-sdk/core': 0.4.0 ai: 4.0.3 + '@goat-sdk/core@0.3.8': + resolution: {integrity: sha512-1H8Cziyjj3bN78M4GETGN8+/fAQhtTPqMowSyAgIZtC/MGWvf41H2SR0FNba/xhfCOALhb0UfhGOsXCswvM5iA==} + engines: {node: '>=20.12.2 <21', npm: please-use-pnpm, pnpm: '>=9', yarn: please-use-pnpm} + '@goat-sdk/core@0.4.0': resolution: {integrity: sha512-x7TVQ+3IS8bS+44O+ZkbS2R6IDXO0dOcRNWe5psU8Aqrb7/48Fe1ILN2Pif0sv34y1WkPYPlqoPINl/TiatIVQ==} + '@goat-sdk/plugin-coingecko@0.1.4': + resolution: {integrity: sha512-i85v/SeCXB7/fcqZKc0hV68/3FrUAHJSL4N5AUp5OPauzV5kq4Ecn0WjeDZEHX8iCEEY1NZSZ47yweDckAhjhA==} + peerDependencies: + '@goat-sdk/core': 0.3.14 + viem: 2.21.58 + + '@goat-sdk/plugin-erc20@0.1.7': + resolution: {integrity: sha512-UDd6pXIBmpCWW7QIFxM5rJPta4tWqkys8P1sAt1kqabAndx+GaczhNUPwSdV1MH77BNtcyGZ6+HoeirskiV//Q==} + engines: {node: '>=20.12.2 <21', npm: please-use-pnpm, pnpm: '>=9', yarn: please-use-pnpm} + peerDependencies: + '@goat-sdk/core': 0.3.8 + viem: 2.21.58 + '@goat-sdk/plugin-erc20@0.2.2': resolution: {integrity: sha512-uobj8A2GRAHAU8PNY9Be0iA8p+311zRDIRKHRQX0uooCWD4CxD6iMj99Q4RvBl8Es+Kc7JMQPRoZzMLawJUSJw==} peerDependencies: @@ -5466,6 +5534,13 @@ packages: peerDependencies: '@goat-sdk/core': 0.4.0 + '@goat-sdk/wallet-viem@0.1.3': + resolution: {integrity: sha512-2uofsH/dVmeJk/4V2/tJ1rDk6/ZFQlthUO50tg366hjq0vjINJXMQqYGwSLnv5Z3PMmdfPCSd5xikFEfA+1ZZw==} + engines: {node: '>=20.12.2 <21', npm: please-use-pnpm, pnpm: '>=9', yarn: please-use-pnpm} + peerDependencies: + '@goat-sdk/core': 0.3.4 + viem: 2.21.58 + '@goat-sdk/wallet-viem@0.2.0': resolution: {integrity: sha512-x9FTUg9/ZhJyx8tQMAuIGmoFfRkmyDge78yvd9CTK6SQTiYQ/Hio7rAmHjLE95lElXb6EumZu7R0IlX3m/SGSw==} peerDependencies: @@ -5816,8 +5891,8 @@ packages: peerDependencies: '@langchain/core': '>=0.2.31 <0.4.0' - '@langchain/langgraph-sdk@0.0.33': - resolution: {integrity: sha512-l/hRbI6roLzplBXy2VyDUwqY1TkK7RcjPmrMUuVdvCCH4LTwLfIXh/G1kHatNiN7VUTskw0FkfBbgq6gtj0ang==} + '@langchain/langgraph-sdk@0.0.34': + resolution: {integrity: sha512-Pjnuz2fDK/Ud11bld2dhqA2hLQ9png3fHWfITfxm3plBCtdpFWmOMH4mbHcmgCSTlZXVQv1rIpctPI3E/4sp5A==} '@langchain/langgraph@0.2.39': resolution: {integrity: sha512-zoQT5LViPlB5hRS7RNwixcAonUBAHcW+IzVkGR/4vcKoE49z5rPBdZsWjJ6b1YIV1K2bdSDJWl5KSEHilvnR1Q==} @@ -8440,8 +8515,8 @@ packages: resolution: {integrity: sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==} engines: {node: '>=18.0.0'} - '@smithy/util-waiter@4.0.0': - resolution: {integrity: sha512-C8dSfGmZH0ecrmnJOw4aDXJ47krihnUtee8eDZ2fA+28wTjD4TVM3L/bBQYnBBlDVWcYzldLV7loPRsPc1kERg==} + '@smithy/util-waiter@4.0.1': + resolution: {integrity: sha512-PiLI5OMSDOw0IyA+lB8Ta0CIgaJuIyXE97Khvrk1G1ab71WbMTruzLKP9j3nS6QJScGirkUVN9sTOhZHU8q3OQ==} engines: {node: '>=18.0.0'} '@solana-developers/helpers@2.5.6': @@ -13245,8 +13320,8 @@ packages: resolution: {integrity: sha512-2kCCtc+JvcZ86IGAz3Z2Y0A1baIz9fL31pH/0S1IqZr9Iwnjq8izfPtrCyQKO6TLMPELLsQMre7VDqeIKCsHkA==} engines: {node: '>=18'} - flash-sdk@2.25.0: - resolution: {integrity: sha512-n7SUVztt/E3s0i6Nfh/tuRi9IEe8kYLyIhyFGuNmaddducSvsqllGkC15xJjZV9petC/YDnAqF+y/CoSJ7aKIg==} + flash-sdk@2.25.1: + resolution: {integrity: sha512-n9hGhJ1uMpMw7xUVZ6cqaGpbGgcLZqyh0jMlXWcqT2mPfLtVL16n2bSEOCmik/rx9jSizixCG9l9cKpeVSi4zg==} flat-cache@3.2.0: resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} @@ -16687,8 +16762,8 @@ packages: zod: optional: true - openai@4.77.3: - resolution: {integrity: sha512-wLDy4+KWHz31HRFMW2+9KQuVuT2QWhs0z94w1Gm1h2Ut9vIHr9/rHZggbykZEfyiaJRVgw8ZS9K6AylDWzvPYw==} + openai@4.77.4: + resolution: {integrity: sha512-rShjKsZ/HXm1cSxXt6iFeZxiCohrVShawt0aRRQmbb+z/EXcH4OouyQZP1ShyZMb63LJajpl8aGw3DzEi8Wh9Q==} hasBin: true peerDependencies: zod: ^3.23.8 @@ -21643,7 +21718,7 @@ snapshots: '@ai-sdk/provider-utils': 1.0.22(zod@3.23.8) zod: 3.23.8 - '@ai-sdk/openai@1.0.14(zod@3.24.1)': + '@ai-sdk/openai@1.0.15(zod@3.24.1)': dependencies: '@ai-sdk/provider': 1.0.4 '@ai-sdk/provider-utils': 2.0.6(zod@3.24.1) @@ -22236,7 +22311,7 @@ snapshots: '@smithy/util-retry': 4.0.0 '@smithy/util-stream': 4.0.0 '@smithy/util-utf8': 4.0.0 - '@smithy/util-waiter': 4.0.0 + '@smithy/util-waiter': 4.0.1 tslib: 2.8.1 transitivePeerDependencies: - aws-crt @@ -26398,11 +26473,35 @@ snapshots: ai: 4.0.30(react@18.3.1)(zod@3.23.8) zod: 3.23.8 + '@goat-sdk/core@0.3.8(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10)': + dependencies: + '@solana/web3.js': 1.95.5(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) + abitype: 1.0.8(typescript@5.7.2)(zod@3.23.8) + viem: 2.21.58(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.23.8) + zod: 3.23.8 + transitivePeerDependencies: + - bufferutil + - encoding + - typescript + - utf-8-validate + '@goat-sdk/core@0.4.0': dependencies: reflect-metadata: 0.2.2 zod: 3.23.8 + '@goat-sdk/plugin-coingecko@0.1.4(@goat-sdk/core@0.3.8(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10))(viem@2.21.58(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.23.8))': + dependencies: + '@goat-sdk/core': 0.3.8(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10) + viem: 2.21.58(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.23.8) + zod: 3.23.8 + + '@goat-sdk/plugin-erc20@0.1.7(@goat-sdk/core@0.3.8(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10))(viem@2.21.58(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.23.8))': + dependencies: + '@goat-sdk/core': 0.3.8(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10) + viem: 2.21.58(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.23.8) + zod: 3.23.8 + '@goat-sdk/plugin-erc20@0.2.2(@goat-sdk/core@0.4.0)(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(viem@2.21.58(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.23.8))': dependencies: '@goat-sdk/core': 0.4.0 @@ -26436,6 +26535,11 @@ snapshots: - typescript - utf-8-validate + '@goat-sdk/wallet-viem@0.1.3(@goat-sdk/core@0.3.8(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10))(viem@2.21.58(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.23.8))': + dependencies: + '@goat-sdk/core': 0.3.8(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.7.2)(utf-8-validate@5.0.10) + viem: 2.21.58(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.23.8) + '@goat-sdk/wallet-viem@0.2.0(@goat-sdk/wallet-evm@0.2.0(@goat-sdk/core@0.4.0)(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10))(viem@2.21.58(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10)(zod@3.23.8))': dependencies: '@goat-sdk/wallet-evm': 0.2.0(@goat-sdk/core@0.4.0)(bufferutil@4.0.9)(typescript@5.7.2)(utf-8-validate@5.0.10) @@ -26924,14 +27028,14 @@ snapshots: transitivePeerDependencies: - openai - '@langchain/core@0.3.27(openai@4.77.3(encoding@0.1.13)(zod@3.24.1))': + '@langchain/core@0.3.27(openai@4.77.4(encoding@0.1.13)(zod@3.24.1))': dependencies: '@cfworker/json-schema': 4.1.0 ansi-styles: 5.2.0 camelcase: 6.3.0 decamelize: 1.2.0 js-tiktoken: 1.0.15 - langsmith: 0.2.14(openai@4.77.3(encoding@0.1.13)(zod@3.24.1)) + langsmith: 0.2.14(openai@4.77.4(encoding@0.1.13)(zod@3.24.1)) mustache: 4.2.0 p-queue: 6.6.2 p-retry: 4.6.2 @@ -26952,33 +27056,33 @@ snapshots: - encoding optional: true - '@langchain/groq@0.1.2(@langchain/core@0.3.27(openai@4.77.3(encoding@0.1.13)(zod@3.24.1)))(encoding@0.1.13)': + '@langchain/groq@0.1.2(@langchain/core@0.3.27(openai@4.77.4(encoding@0.1.13)(zod@3.24.1)))(encoding@0.1.13)': dependencies: - '@langchain/core': 0.3.27(openai@4.77.3(encoding@0.1.13)(zod@3.24.1)) - '@langchain/openai': 0.3.16(@langchain/core@0.3.27(openai@4.77.3(encoding@0.1.13)(zod@3.24.1)))(encoding@0.1.13) + '@langchain/core': 0.3.27(openai@4.77.4(encoding@0.1.13)(zod@3.24.1)) + '@langchain/openai': 0.3.16(@langchain/core@0.3.27(openai@4.77.4(encoding@0.1.13)(zod@3.24.1)))(encoding@0.1.13) groq-sdk: 0.5.0(encoding@0.1.13) zod: 3.23.8 zod-to-json-schema: 3.24.1(zod@3.23.8) transitivePeerDependencies: - encoding - '@langchain/langgraph-checkpoint@0.0.13(@langchain/core@0.3.27(openai@4.77.3(encoding@0.1.13)(zod@3.24.1)))': + '@langchain/langgraph-checkpoint@0.0.13(@langchain/core@0.3.27(openai@4.77.4(encoding@0.1.13)(zod@3.24.1)))': dependencies: - '@langchain/core': 0.3.27(openai@4.77.3(encoding@0.1.13)(zod@3.24.1)) + '@langchain/core': 0.3.27(openai@4.77.4(encoding@0.1.13)(zod@3.24.1)) uuid: 10.0.0 - '@langchain/langgraph-sdk@0.0.33': + '@langchain/langgraph-sdk@0.0.34': dependencies: '@types/json-schema': 7.0.15 p-queue: 6.6.2 p-retry: 4.6.2 uuid: 9.0.1 - '@langchain/langgraph@0.2.39(@langchain/core@0.3.27(openai@4.77.3(encoding@0.1.13)(zod@3.24.1)))': + '@langchain/langgraph@0.2.39(@langchain/core@0.3.27(openai@4.77.4(encoding@0.1.13)(zod@3.24.1)))': dependencies: - '@langchain/core': 0.3.27(openai@4.77.3(encoding@0.1.13)(zod@3.24.1)) - '@langchain/langgraph-checkpoint': 0.0.13(@langchain/core@0.3.27(openai@4.77.3(encoding@0.1.13)(zod@3.24.1))) - '@langchain/langgraph-sdk': 0.0.33 + '@langchain/core': 0.3.27(openai@4.77.4(encoding@0.1.13)(zod@3.24.1)) + '@langchain/langgraph-checkpoint': 0.0.13(@langchain/core@0.3.27(openai@4.77.4(encoding@0.1.13)(zod@3.24.1))) + '@langchain/langgraph-sdk': 0.0.34 uuid: 10.0.0 zod: 3.23.8 @@ -26986,17 +27090,17 @@ snapshots: dependencies: '@langchain/core': 0.3.27(openai@4.73.0(encoding@0.1.13)(zod@3.23.8)) js-tiktoken: 1.0.15 - openai: 4.77.3(encoding@0.1.13)(zod@3.23.8) + openai: 4.77.4(encoding@0.1.13)(zod@3.23.8) zod: 3.23.8 zod-to-json-schema: 3.24.1(zod@3.23.8) transitivePeerDependencies: - encoding - '@langchain/openai@0.3.16(@langchain/core@0.3.27(openai@4.77.3(encoding@0.1.13)(zod@3.24.1)))(encoding@0.1.13)': + '@langchain/openai@0.3.16(@langchain/core@0.3.27(openai@4.77.4(encoding@0.1.13)(zod@3.24.1)))(encoding@0.1.13)': dependencies: - '@langchain/core': 0.3.27(openai@4.77.3(encoding@0.1.13)(zod@3.24.1)) + '@langchain/core': 0.3.27(openai@4.77.4(encoding@0.1.13)(zod@3.24.1)) js-tiktoken: 1.0.15 - openai: 4.77.3(encoding@0.1.13)(zod@3.23.8) + openai: 4.77.4(encoding@0.1.13)(zod@3.23.8) zod: 3.23.8 zod-to-json-schema: 3.24.1(zod@3.23.8) transitivePeerDependencies: @@ -27007,9 +27111,9 @@ snapshots: '@langchain/core': 0.3.27(openai@4.73.0(encoding@0.1.13)(zod@3.23.8)) js-tiktoken: 1.0.15 - '@langchain/textsplitters@0.1.0(@langchain/core@0.3.27(openai@4.77.3(encoding@0.1.13)(zod@3.24.1)))': + '@langchain/textsplitters@0.1.0(@langchain/core@0.3.27(openai@4.77.4(encoding@0.1.13)(zod@3.24.1)))': dependencies: - '@langchain/core': 0.3.27(openai@4.77.3(encoding@0.1.13)(zod@3.24.1)) + '@langchain/core': 0.3.27(openai@4.77.4(encoding@0.1.13)(zod@3.24.1)) js-tiktoken: 1.0.15 '@leichtgewicht/ip-codec@2.0.5': {} @@ -30920,7 +31024,7 @@ snapshots: '@smithy/util-buffer-from': 4.0.0 tslib: 2.8.1 - '@smithy/util-waiter@4.0.0': + '@smithy/util-waiter@4.0.1': dependencies: '@smithy/abort-controller': 4.0.0 '@smithy/types': 4.0.0 @@ -31384,7 +31488,7 @@ snapshots: dependencies: '@babel/runtime': 7.26.0 '@noble/curves': 1.8.0 - '@noble/hashes': 1.5.0 + '@noble/hashes': 1.7.0 '@solana/buffer-layout': 4.0.1 agentkeepalive: 4.6.0 bigint-buffer: 1.1.5 @@ -37814,7 +37918,7 @@ snapshots: semver-regex: 4.0.5 super-regex: 1.0.0 - flash-sdk@2.25.0(@swc/core@1.10.6(@swc/helpers@0.5.15))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10): + flash-sdk@2.25.1(@swc/core@1.10.6(@swc/helpers@0.5.15))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10): dependencies: '@coral-xyz/anchor': 0.27.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) '@pythnetwork/client': 2.22.0(@solana/web3.js@1.95.8(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) @@ -40544,15 +40648,15 @@ snapshots: inherits: 2.0.4 stream-splicer: 2.0.1 - langchain@0.3.10(@langchain/core@0.3.27(openai@4.77.3(encoding@0.1.13)(zod@3.24.1)))(@langchain/groq@0.1.2(@langchain/core@0.3.27(openai@4.77.3(encoding@0.1.13)(zod@3.24.1)))(encoding@0.1.13))(axios@1.7.9)(encoding@0.1.13)(handlebars@4.7.8)(openai@4.77.3(encoding@0.1.13)(zod@3.24.1)): + langchain@0.3.10(@langchain/core@0.3.27(openai@4.77.4(encoding@0.1.13)(zod@3.24.1)))(@langchain/groq@0.1.2(@langchain/core@0.3.27(openai@4.77.4(encoding@0.1.13)(zod@3.24.1)))(encoding@0.1.13))(axios@1.7.9)(encoding@0.1.13)(handlebars@4.7.8)(openai@4.77.4(encoding@0.1.13)(zod@3.24.1)): dependencies: - '@langchain/core': 0.3.27(openai@4.77.3(encoding@0.1.13)(zod@3.24.1)) - '@langchain/openai': 0.3.16(@langchain/core@0.3.27(openai@4.77.3(encoding@0.1.13)(zod@3.24.1)))(encoding@0.1.13) - '@langchain/textsplitters': 0.1.0(@langchain/core@0.3.27(openai@4.77.3(encoding@0.1.13)(zod@3.24.1))) + '@langchain/core': 0.3.27(openai@4.77.4(encoding@0.1.13)(zod@3.24.1)) + '@langchain/openai': 0.3.16(@langchain/core@0.3.27(openai@4.77.4(encoding@0.1.13)(zod@3.24.1)))(encoding@0.1.13) + '@langchain/textsplitters': 0.1.0(@langchain/core@0.3.27(openai@4.77.4(encoding@0.1.13)(zod@3.24.1))) js-tiktoken: 1.0.15 js-yaml: 4.1.0 jsonpointer: 5.0.1 - langsmith: 0.2.14(openai@4.77.3(encoding@0.1.13)(zod@3.24.1)) + langsmith: 0.2.14(openai@4.77.4(encoding@0.1.13)(zod@3.24.1)) openapi-types: 12.1.3 p-retry: 4.6.2 uuid: 10.0.0 @@ -40560,7 +40664,7 @@ snapshots: zod: 3.23.8 zod-to-json-schema: 3.24.1(zod@3.23.8) optionalDependencies: - '@langchain/groq': 0.1.2(@langchain/core@0.3.27(openai@4.77.3(encoding@0.1.13)(zod@3.24.1)))(encoding@0.1.13) + '@langchain/groq': 0.1.2(@langchain/core@0.3.27(openai@4.77.4(encoding@0.1.13)(zod@3.24.1)))(encoding@0.1.13) axios: 1.7.9(debug@4.4.0) handlebars: 4.7.8 transitivePeerDependencies: @@ -40609,7 +40713,7 @@ snapshots: optionalDependencies: openai: 4.73.0(encoding@0.1.13)(zod@3.23.8) - langsmith@0.2.14(openai@4.77.3(encoding@0.1.13)(zod@3.24.1)): + langsmith@0.2.14(openai@4.77.4(encoding@0.1.13)(zod@3.24.1)): dependencies: '@types/uuid': 10.0.0 commander: 10.0.1 @@ -40618,7 +40722,7 @@ snapshots: semver: 7.6.3 uuid: 10.0.0 optionalDependencies: - openai: 4.77.3(encoding@0.1.13)(zod@3.24.1) + openai: 4.77.4(encoding@0.1.13)(zod@3.24.1) latest-version@7.0.0: dependencies: @@ -42731,7 +42835,7 @@ snapshots: transitivePeerDependencies: - encoding - openai@4.77.3(encoding@0.1.13)(zod@3.23.8): + openai@4.77.4(encoding@0.1.13)(zod@3.23.8): dependencies: '@types/node': 18.19.70 '@types/node-fetch': 2.6.12 @@ -42745,7 +42849,7 @@ snapshots: transitivePeerDependencies: - encoding - openai@4.77.3(encoding@0.1.13)(zod@3.24.1): + openai@4.77.4(encoding@0.1.13)(zod@3.24.1): dependencies: '@types/node': 18.19.70 '@types/node-fetch': 2.6.12 @@ -45729,14 +45833,14 @@ snapshots: solana-agent-kit@1.3.7(@noble/hashes@1.7.0)(@swc/core@1.10.6(@swc/helpers@0.5.15))(axios@1.7.9)(borsh@2.0.0)(buffer@6.0.3)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(handlebars@4.7.8)(jiti@2.4.2)(react@18.3.1)(sodium-native@3.4.1)(typescript@5.7.2)(utf-8-validate@5.0.10): dependencies: - '@ai-sdk/openai': 1.0.14(zod@3.24.1) + '@ai-sdk/openai': 1.0.15(zod@3.24.1) '@bonfida/spl-name-service': 3.0.7(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) '@cks-systems/manifest-sdk': 0.1.59(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(jiti@2.4.2)(typescript@5.7.2)(utf-8-validate@5.0.10) '@coral-xyz/anchor': 0.29.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) - '@langchain/core': 0.3.27(openai@4.77.3(encoding@0.1.13)(zod@3.24.1)) - '@langchain/groq': 0.1.2(@langchain/core@0.3.27(openai@4.77.3(encoding@0.1.13)(zod@3.24.1)))(encoding@0.1.13) - '@langchain/langgraph': 0.2.39(@langchain/core@0.3.27(openai@4.77.3(encoding@0.1.13)(zod@3.24.1))) - '@langchain/openai': 0.3.16(@langchain/core@0.3.27(openai@4.77.3(encoding@0.1.13)(zod@3.24.1)))(encoding@0.1.13) + '@langchain/core': 0.3.27(openai@4.77.4(encoding@0.1.13)(zod@3.24.1)) + '@langchain/groq': 0.1.2(@langchain/core@0.3.27(openai@4.77.4(encoding@0.1.13)(zod@3.24.1)))(encoding@0.1.13) + '@langchain/langgraph': 0.2.39(@langchain/core@0.3.27(openai@4.77.4(encoding@0.1.13)(zod@3.24.1))) + '@langchain/openai': 0.3.16(@langchain/core@0.3.27(openai@4.77.4(encoding@0.1.13)(zod@3.24.1)))(encoding@0.1.13) '@lightprotocol/compressed-token': 0.17.1(@lightprotocol/stateless.js@0.17.1(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) '@lightprotocol/stateless.js': 0.17.1(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) '@metaplex-foundation/mpl-core': 1.1.1(@metaplex-foundation/umi@0.9.2)(@noble/hashes@1.7.0) @@ -45760,10 +45864,10 @@ snapshots: chai: 5.1.2 decimal.js: 10.4.3 dotenv: 16.4.7 - flash-sdk: 2.25.0(@swc/core@1.10.6(@swc/helpers@0.5.15))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) + flash-sdk: 2.25.1(@swc/core@1.10.6(@swc/helpers@0.5.15))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) form-data: 4.0.1 - langchain: 0.3.10(@langchain/core@0.3.27(openai@4.77.3(encoding@0.1.13)(zod@3.24.1)))(@langchain/groq@0.1.2(@langchain/core@0.3.27(openai@4.77.3(encoding@0.1.13)(zod@3.24.1)))(encoding@0.1.13))(axios@1.7.9)(encoding@0.1.13)(handlebars@4.7.8)(openai@4.77.3(encoding@0.1.13)(zod@3.24.1)) - openai: 4.77.3(encoding@0.1.13)(zod@3.24.1) + langchain: 0.3.10(@langchain/core@0.3.27(openai@4.77.4(encoding@0.1.13)(zod@3.24.1)))(@langchain/groq@0.1.2(@langchain/core@0.3.27(openai@4.77.4(encoding@0.1.13)(zod@3.24.1)))(encoding@0.1.13))(axios@1.7.9)(encoding@0.1.13)(handlebars@4.7.8)(openai@4.77.4(encoding@0.1.13)(zod@3.24.1)) + openai: 4.77.4(encoding@0.1.13)(zod@3.24.1) typedoc: 0.27.6(typescript@5.7.2) zod: 3.24.1 transitivePeerDependencies: @@ -47606,25 +47710,6 @@ 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 From b2abd16f6bc54e7de4401ac9f23bc1943cf99b2a Mon Sep 17 00:00:00 2001 From: Shakker Nerd Date: Wed, 8 Jan 2025 18:07:11 +0000 Subject: [PATCH 3/3] chore: fix build on plugin rabbi trader --- packages/plugin-rabbi-trader/package.json | 14 +++++++------- pnpm-lock.yaml | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/plugin-rabbi-trader/package.json b/packages/plugin-rabbi-trader/package.json index 69e8c7a736d..4b73dacae6a 100644 --- a/packages/plugin-rabbi-trader/package.json +++ b/packages/plugin-rabbi-trader/package.json @@ -6,18 +6,18 @@ "types": "dist/index.d.ts", "dependencies": { "@elizaos/core": "workspace:*", - "@elizaos/client-twitter":"workspace:*", - "@elizaos/plugin-solana":"workspace:*", - "@elizaos/plugin-trustdb":"workspace:*", + "@elizaos/client-twitter": "workspace:*", + "@elizaos/plugin-solana": "workspace:*", + "@elizaos/plugin-trustdb": "workspace:*", "@solana/web3.js": "^1.87.6", - "zod":"3.23.8", + "zod": "3.23.8", "@goat-sdk/core": "0.3.8", "@goat-sdk/plugin-erc20": "0.1.7", "@goat-sdk/wallet-viem": "0.1.3", - "node-cache": "^5.1.2", - "bignumber": "1.1.0", + "node-cache": "^5.1.2", + "bignumber": "1.1.0", "bignumber.js": "9.1.2", - "@goat-sdk/plugin-coingecko":"0.1.4", + "@goat-sdk/plugin-coingecko": "0.1.4", "tsup": "8.3.5", "ws": "^8.0.0" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b456169188b..5e43a7474a0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -37706,7 +37706,7 @@ snapshots: extract-zip@2.0.1: dependencies: - debug: 4.3.4 + debug: 4.4.0(supports-color@8.1.1) get-stream: 5.2.0 yauzl: 2.10.0 optionalDependencies: