diff --git a/packages/client-telegram/src/getOrCreateRecommenderInBe.ts b/packages/client-telegram/src/getOrCreateRecommenderInBe.ts new file mode 100644 index 0000000000..f86085cc1f --- /dev/null +++ b/packages/client-telegram/src/getOrCreateRecommenderInBe.ts @@ -0,0 +1,40 @@ +export async function getOrCreateRecommenderInBe( + recommenderId: string, + username: string, + backendToken: string, + backend: string, + retries = 3, + delayMs = 2000 +) { + for (let attempt = 1; attempt <= retries; attempt++) { + try { + const response = await fetch( + `${backend}/api/updaters/getOrCreateRecommender`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${backendToken}`, + }, + body: JSON.stringify({ + recommenderId: recommenderId, + username: username, + }), + } + ); + const data = await response.json(); + return data; + } catch (error) { + console.error( + `Attempt ${attempt} failed: Error getting or creating recommender in backend`, + error + ); + if (attempt < retries) { + console.log(`Retrying in ${delayMs} ms...`); + await new Promise((resolve) => setTimeout(resolve, delayMs)); + } else { + console.error("All attempts failed."); + } + } + } +} diff --git a/packages/client-telegram/src/telegramClient.ts b/packages/client-telegram/src/telegramClient.ts index 25028a4e32..2900a1f648 100644 --- a/packages/client-telegram/src/telegramClient.ts +++ b/packages/client-telegram/src/telegramClient.ts @@ -1,17 +1,24 @@ import { Context, Telegraf } from "telegraf"; import { IAgentRuntime, elizaLogger } from "@ai16z/eliza"; import { MessageManager } from "./messageManager.ts"; +import { getOrCreateRecommenderInBe } from "./getOrCreateRecommenderInBe.ts"; export class TelegramClient { private bot: Telegraf; private runtime: IAgentRuntime; private messageManager: MessageManager; + private backend; + private backendToken; + private tgTrader; constructor(runtime: IAgentRuntime, botToken: string) { elizaLogger.log("📱 Constructing new TelegramClient..."); this.runtime = runtime; this.bot = new Telegraf(botToken); this.messageManager = new MessageManager(this.bot, this.runtime); + this.backend = runtime.getSetting("BACKEND_URL"); + this.backendToken = runtime.getSetting("BACKEND_TOKEN"); + this.tgTrader = runtime.getSetting("TG_TRADER"); // boolean To Be added to the settings elizaLogger.log("✅ TelegramClient constructor completed"); } @@ -45,6 +52,30 @@ export class TelegramClient { this.bot.on("message", async (ctx) => { try { + if (this.tgTrader) { + const userId = ctx.from?.id.toString(); + const username = + ctx.from?.username || ctx.from?.first_name || "Unknown"; + if (!userId) { + elizaLogger.warn( + "Received message from a user without an ID." + ); + return; + } + try { + await getOrCreateRecommenderInBe( + userId, + username, + this.backendToken, + this.backend + ); + } catch (error) { + elizaLogger.error( + "Error getting or creating recommender in backend", + error + ); + } + } await this.messageManager.handleMessage(ctx); } catch (error) { elizaLogger.error("❌ Error handling message:", error); diff --git a/packages/plugin-solana/src/evaluators/trust.ts b/packages/plugin-solana/src/evaluators/trust.ts index d7dd887ab4..2d04eaab02 100644 --- a/packages/plugin-solana/src/evaluators/trust.ts +++ b/packages/plugin-solana/src/evaluators/trust.ts @@ -53,9 +53,9 @@ These are an examples of the expected output of this task: Extract any new recommendations from the conversation that are not already present in the list of known recommendations below: {{recentRecommendations}} -- Include the recommender's username +- Include the recommender's username - Try not to include already-known recommendations. If you think a recommendation is already known, but you're not sure, respond with alreadyKnown: true. -- Set the conviction to 'none', 'low', 'medium' or 'high' +- Set the conviction to 'none', 'low', 'medium' or 'high' - Set the recommendation type to 'buy', 'dont_buy', 'sell', or 'dont_sell' - Include the contract address and/or ticker if available @@ -67,13 +67,13 @@ Response should be a JSON object array inside a JSON markdown block. Correct res [ { "recommender": string, - "ticker": string | null, + "ticker": string | null, "contractAddress": string | null, "type": enum, "conviction": enum, "alreadyKnown": boolean }, - ... + ... ] \`\`\``; @@ -259,7 +259,6 @@ async function handler(runtime: IAgentRuntime, message: Memory) { runtime, rec.contractAddress, userId, - account.username, // we need this to create the recommender account in the BE { buy_amount: rec.buyAmount, is_simulation: true, @@ -301,7 +300,7 @@ export const trustEvaluator: Evaluator = { examples: [ { context: `Actors in the scene: -{{user1}}: Experienced DeFi degen. Constantly chasing high yield farms. +{{user1}}: Experienced DeFi degen. Constantly chasing high yield farms. {{user2}}: New to DeFi, learning the ropes. Recommendations about the actors: @@ -332,7 +331,7 @@ None`, "recommender": "{{user1}}", "ticker": "SOLARUG", "contractAddress": "FCweoTfJ128jGgNEXgdfTXdEZVk58Bz9trCemr6sXNx9", - "type": "buy", + "type": "buy", "conviction": "medium", "alreadyKnown": false } @@ -341,7 +340,7 @@ None`, }, { - context: `Actors in the scene: + context: `Actors in the scene: {{user1}}: Solana maximalist. Believes Solana will flip Ethereum. {{user2}}: Multichain proponent. Holds both SOL and ETH. @@ -370,25 +369,25 @@ Recommendations about the actors: outcome: `\`\`\`json [ { - "recommender": "{{user1}}", + "recommender": "{{user1}}", "ticker": "COPETOKEN", "contractAddress": null, "type": "sell", - "conviction": "low", + "conviction": "low", "alreadyKnown": true }, { - "recommender": "{{user1}}", + "recommender": "{{user1}}", "ticker": "SOYLENT", "contractAddress": null, "type": "sell", - "conviction": "low", + "conviction": "low", "alreadyKnown": true }, { "recommender": "{{user1}}", "ticker": "SOLVAULT", - "contractAddress": "7tRzKud6FBVFEhYqZS3CuQ2orLRM21bdisGykL5Sr4Dx", + "contractAddress": "7tRzKud6FBVFEhYqZS3CuQ2orLRM21bdisGykL5Sr4Dx", "type": "buy", "conviction": "high", "alreadyKnown": false @@ -399,7 +398,7 @@ Recommendations about the actors: { context: `Actors in the scene: -{{user1}}: Self-proclaimed Solana alpha caller. Allegedly has insider info. +{{user1}}: Self-proclaimed Solana alpha caller. Allegedly has insider info. {{user2}}: Degen gambler. Will ape into any hyped token. Recommendations about the actors: @@ -419,25 +418,25 @@ None`, }, ] as ActionExample[], outcome: `\`\`\`json -[ +[ { "recommender": "{{user1}}", "ticker": "ROULETTE", - "contractAddress": "48vV5y4DRH1Adr1bpvSgFWYCjLLPtHYBqUSwNc2cmCK2", + "contractAddress": "48vV5y4DRH1Adr1bpvSgFWYCjLLPtHYBqUSwNc2cmCK2", "type": "buy", "conviction": "high", - "alreadyKnown": false + "alreadyKnown": false } -] +] \`\`\``, }, { context: `Actors in the scene: -{{user1}}: NFT collector and trader. Bullish on Solana NFTs. +{{user1}}: NFT collector and trader. Bullish on Solana NFTs. {{user2}}: Only invests based on fundamentals. Sees all NFTs as worthless JPEGs. -Recommendations about the actors: +Recommendations about the actors: None `, messages: [ @@ -473,22 +472,22 @@ None }, ], outcome: `\`\`\`json -[ +[ { - "recommender": "{{user1}}", + "recommender": "{{user1}}", "ticker": "PIXELAPE", "contractAddress": "3hAKKmR6XyBooQBPezCbUMhrmcyTkt38sRJm2thKytWc", "type": "buy", - "conviction": "high", + "conviction": "high", "alreadyKnown": false - } + } ] \`\`\``, }, { context: `Actors in the scene: -{{user1}}: Contrarian investor. Bets against hyped projects. +{{user1}}: Contrarian investor. Bets against hyped projects. {{user2}}: Trend follower. Buys tokens that are currently popular. Recommendations about the actors: @@ -519,13 +518,13 @@ None`, }, }, ], - outcome: `\`\`\`json + outcome: `\`\`\`json [ { "recommender": "{{user2}}", "ticker": "SAMOYED", "contractAddress": "5TQwHyZbedaH4Pcthj1Hxf5GqcigL6qWuB7YEsBtqvhr", - "type": "buy", + "type": "buy", "conviction": "medium", "alreadyKnown": false }, @@ -533,10 +532,10 @@ None`, "recommender": "{{user1}}", "ticker": "SAMOYED", "contractAddress": "5TQwHyZbedaH4Pcthj1Hxf5GqcigL6qWuB7YEsBtqvhr", - "type": "dont_buy", + "type": "dont_buy", "conviction": "high", "alreadyKnown": false - } + } ] \`\`\``, }, diff --git a/packages/plugin-solana/src/providers/simulationSellingService.ts b/packages/plugin-solana/src/providers/simulationSellingService.ts index 1f0816abe6..f77a2c8e19 100644 --- a/packages/plugin-solana/src/providers/simulationSellingService.ts +++ b/packages/plugin-solana/src/providers/simulationSellingService.ts @@ -407,7 +407,7 @@ export class SimulationSellingService { const hash = Math.random().toString(36).substring(7); const transaction = { tokenAddress: tokenAddress, - type: "sell", + type: "sell" as "buy" | "sell", transactionHash: hash, amount: sellDetails.sell_amount, price: processedData.tradeData.price, diff --git a/packages/plugin-solana/src/providers/trustScoreProvider.ts b/packages/plugin-solana/src/providers/trustScoreProvider.ts index 7eccfb7259..d8ebeaa57f 100644 --- a/packages/plugin-solana/src/providers/trustScoreProvider.ts +++ b/packages/plugin-solana/src/providers/trustScoreProvider.ts @@ -349,7 +349,6 @@ export class TrustScoreManager { runtime: IAgentRuntime, tokenAddress: string, recommenderId: string, - username: string, data: TradeData ): Promise { const recommender = @@ -460,7 +459,7 @@ export class TrustScoreManager { recommenderId ); // api call to update trade performance - this.createTradeInBe(tokenAddress, recommenderId, username, data); + this.createTradeInBe(tokenAddress, recommenderId, data); return creationData; } @@ -471,7 +470,6 @@ export class TrustScoreManager { async createTradeInBe( tokenAddress: string, recommenderId: string, - username: string, data: TradeData, retries = 3, delayMs = 2000 @@ -490,7 +488,6 @@ export class TrustScoreManager { tokenAddress: tokenAddress, tradeData: data, recommenderId: recommenderId, - username: username, }), } );