From f354fbd6c69a23b9f1b8459e96b7d950265e985f Mon Sep 17 00:00:00 2001
From: MarcoMandar <malicemandar@gmail.com>
Date: Tue, 19 Nov 2024 07:28:00 +0200
Subject: [PATCH 01/12] token balance, transactions, data simulation update on
 buys and sells

Signed-off-by: MarcoMandar <malicemandar@gmail.com>
---
 .../src/providers/trustScoreProvider.ts       |  40 ++++++
 .../src/adapters/trustScoreDatabase.ts        | 120 ++++++++++++++++++
 2 files changed, 160 insertions(+)

diff --git a/packages/plugin-solana/src/providers/trustScoreProvider.ts b/packages/plugin-solana/src/providers/trustScoreProvider.ts
index 88c2b97df01..fcb98d394e4 100644
--- a/packages/plugin-solana/src/providers/trustScoreProvider.ts
+++ b/packages/plugin-solana/src/providers/trustScoreProvider.ts
@@ -351,10 +351,14 @@ export class TrustScoreManager {
             new PublicKey(Wallet!)
         );
 
+        let tokensBalance = 0;
         const prices = await wallet.fetchPrices(runtime);
         const solPrice = prices.solana.usd;
         const buySol = data.buy_amount / parseFloat(solPrice);
         const buy_value_usd = data.buy_amount * processedData.tradeData.price;
+        const token = await this.tokenProvider.fetchTokenTradeData();
+        const tokenPrice = token.price;
+        tokensBalance = buy_value_usd / tokenPrice;
 
         const creationData = {
             token_address: tokenAddress,
@@ -383,6 +387,23 @@ export class TrustScoreManager {
             rapidDump: false,
         };
         this.trustScoreDb.addTradePerformance(creationData, data.is_simulation);
+
+        if (data.is_simulation) {
+            // If the trade is a simulation update the balance
+            this.trustScoreDb.updateTokenBalance(tokenAddress, tokensBalance);
+            // generate some random hash for simulations
+            const hash = Math.random().toString(36).substring(7);
+            const transaction = {
+                tokenAddress: tokenAddress,
+                type: "buy",
+                transactionHash: hash,
+                amount: data.buy_amount,
+                price: processedData.tradeData.price,
+                isSimulation: true,
+                timestamp: new Date().toISOString(),
+            };
+            this.trustScoreDb.addTransaction(transaction);
+        }
         // api call to update trade performance
         this.createTradeInBe(tokenAddress, recommenderId, data);
         return creationData;
@@ -507,6 +528,25 @@ export class TrustScoreManager {
             sellDetailsData,
             isSimulation
         );
+        if (isSimulation) {
+            // If the trade is a simulation update the balance
+            const oldBalance = this.trustScoreDb.getTokenBalance(tokenAddress);
+            const tokenBalance = oldBalance - sellDetails.sell_amount;
+            this.trustScoreDb.updateTokenBalance(tokenAddress, tokenBalance);
+            // generate some random hash for simulations
+            const hash = Math.random().toString(36).substring(7);
+            const transaction = {
+                tokenAddress: tokenAddress,
+                type: "sell",
+                transactionHash: hash,
+                amount: sellDetails.sell_amount,
+                price: processedData.tradeData.price,
+                isSimulation: true,
+                timestamp: new Date().toISOString(),
+            };
+            this.trustScoreDb.addTransaction(transaction);
+        }
+
         return sellDetailsData;
     }
 
diff --git a/packages/plugin-trustdb/src/adapters/trustScoreDatabase.ts b/packages/plugin-trustdb/src/adapters/trustScoreDatabase.ts
index 51b44b9eb25..5fd6e3d8bb7 100644
--- a/packages/plugin-trustdb/src/adapters/trustScoreDatabase.ts
+++ b/packages/plugin-trustdb/src/adapters/trustScoreDatabase.ts
@@ -40,6 +40,7 @@ export interface TokenPerformance {
     rapidDump: boolean;
     suspiciousVolume: boolean;
     validationTrust: number;
+    balance: number;
     lastUpdated: Date;
 }
 
@@ -120,9 +121,20 @@ interface TokenPerformanceRow {
     rapid_dump: number;
     suspicious_volume: number;
     validation_trust: number;
+    balance: number;
     last_updated: string;
 }
 
+interface Transaction {
+    tokenAddress: string;
+    transactionHash: string;
+    type: "buy" | "sell";
+    amount: number;
+    price: number;
+    isSimulation: boolean;
+    timestamp: string;
+}
+
 export class TrustScoreDatabase {
     private db: Database;
 
@@ -192,6 +204,7 @@ export class TrustScoreDatabase {
                 rapid_dump BOOLEAN DEFAULT FALSE,
                 suspicious_volume BOOLEAN DEFAULT FALSE,
                 validation_trust REAL DEFAULT 0,
+                balance REAL DEFAULT 0,
                 last_updated DATETIME DEFAULT CURRENT_TIMESTAMP
             );
         `);
@@ -289,6 +302,20 @@ export class TrustScoreDatabase {
           FOREIGN KEY (recommender_id) REFERENCES recommenders(id) ON DELETE CASCADE
       );
   `);
+
+        // create transactions table
+        this.db.exec(`
+        CREATE TABLE IF NOT EXISTS transactions (
+            token_address TEXT NOT NULL,
+            transaction_hash TEXT PRIMARY KEY,
+            type TEXT NOT NULL,
+            amount REAL NOT NULL,
+            price REAL NOT NULL,
+            timestamp TEXT NOT NULL,
+            is_simulation BOOLEAN DEFAULT FALSE,
+            FOREIGN KEY (token_address) REFERENCES token_performance(token_address) ON DELETE CASCADE
+        );
+    `);
     }
 
     /**
@@ -749,6 +776,25 @@ export class TrustScoreDatabase {
         }
     }
 
+    // update token balance
+
+    updateTokenBalance(tokenAddress: string, balance: number): boolean {
+        const sql = `
+            UPDATE token_performance
+            SET balance = ?,
+                last_updated = CURRENT_TIMESTAMP
+            WHERE token_address = ?;
+        `;
+        try {
+            this.db.prepare(sql).run(balance, tokenAddress);
+            console.log(`Updated token balance for ${tokenAddress}`);
+            return true;
+        } catch (error) {
+            console.error("Error updating token balance:", error);
+            return false;
+        }
+    }
+
     /**
      * Retrieves token performance metrics.
      * @param tokenAddress Token's address
@@ -776,6 +822,7 @@ export class TrustScoreDatabase {
             rapidDump: row.rapid_dump === 1,
             suspiciousVolume: row.suspicious_volume === 1,
             validationTrust: row.validation_trust,
+            balance: row.balance,
             lastUpdated: new Date(row.last_updated),
         };
     }
@@ -1247,6 +1294,79 @@ export class TrustScoreDatabase {
         };
     }
 
+    // ----- Transactions Methods -----
+    /**
+     * Adds a new transaction to the database.
+     * @param transaction Transaction object
+     * @returns boolean indicating success
+     */
+
+    addTransaction(transaction: Transaction): boolean {
+        const sql = `
+        INSERT INTO transactions (
+            token_address,
+            transaction_hash,
+            type,
+            amount,
+            price,
+            is_simulation,
+            timestamp
+        ) VALUES (?, ?, ?, ?, ?, ?);
+    `;
+        try {
+            this.db
+                .prepare(sql)
+                .run(
+                    transaction.tokenAddress,
+                    transaction.transactionHash,
+                    transaction.type,
+                    transaction.amount,
+                    transaction.price,
+                    transaction.isSimulation,
+                    transaction.timestamp
+                );
+            return true;
+        } catch (error) {
+            console.error("Error adding transaction:", error);
+            return false;
+        }
+    }
+
+    /**
+     * Retrieves all transactions for a specific token.
+     * @param tokenAddress Token's address
+     * @returns Array of Transaction objects
+     */
+    getTransactionsByToken(tokenAddress: string): Transaction[] {
+        const sql = `SELECT * FROM transactions WHERE token_address = ? ORDER BY timestamp DESC;`;
+        const rows = this.db.prepare(sql).all(tokenAddress) as Array<{
+            token_address: string;
+            transaction_hash: string;
+            type: string;
+            amount: number;
+            price: number;
+            is_simulation: boolean;
+            timestamp: string;
+        }>;
+
+        return rows.map((row) => {
+            // Validate and cast 'type' to ensure it matches the expected union type
+            if (row.type !== "buy" && row.type !== "sell") {
+                throw new Error(`Unexpected transaction type: ${row.type}`);
+            }
+
+            return {
+                tokenAddress: row.token_address,
+                transactionHash: row.transaction_hash,
+                type: row.type as "buy" | "sell",
+                amount: row.amount,
+                price: row.price,
+                isSimulation: row.is_simulation,
+                timestamp: new Date(row.timestamp).toISOString(),
+            };
+        });
+    }
+
     /**
      * Close the database connection gracefully.
      */

From ee1ea3495e4c4d2e509a9227eb33acf032c47cfd Mon Sep 17 00:00:00 2001
From: MarcoMandar <malicemandar@gmail.com>
Date: Wed, 20 Nov 2024 02:45:44 +0200
Subject: [PATCH 02/12] include username in createTradePerformance

Signed-off-by: MarcoMandar <malicemandar@gmail.com>
---
 packages/plugin-solana/src/evaluators/trust.ts             | 1 +
 packages/plugin-solana/src/providers/trustScoreProvider.ts | 5 ++++-
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/packages/plugin-solana/src/evaluators/trust.ts b/packages/plugin-solana/src/evaluators/trust.ts
index d4fecefdc94..05e98b75096 100644
--- a/packages/plugin-solana/src/evaluators/trust.ts
+++ b/packages/plugin-solana/src/evaluators/trust.ts
@@ -253,6 +253,7 @@ 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,
diff --git a/packages/plugin-solana/src/providers/trustScoreProvider.ts b/packages/plugin-solana/src/providers/trustScoreProvider.ts
index fcb98d394e4..4478e2c94b6 100644
--- a/packages/plugin-solana/src/providers/trustScoreProvider.ts
+++ b/packages/plugin-solana/src/providers/trustScoreProvider.ts
@@ -338,6 +338,7 @@ export class TrustScoreManager {
         runtime: IAgentRuntime,
         tokenAddress: string,
         recommenderId: string,
+        username: string,
         data: TradeData
     ): Promise<TradePerformance> {
         const recommender =
@@ -405,7 +406,7 @@ export class TrustScoreManager {
             this.trustScoreDb.addTransaction(transaction);
         }
         // api call to update trade performance
-        this.createTradeInBe(tokenAddress, recommenderId, data);
+        this.createTradeInBe(tokenAddress, recommenderId, username, data);
         return creationData;
     }
 
@@ -416,6 +417,7 @@ export class TrustScoreManager {
     async createTradeInBe(
         tokenAddress: string,
         recommenderId: string,
+        username: string,
         data: TradeData,
         retries = 3,
         delayMs = 2000
@@ -434,6 +436,7 @@ export class TrustScoreManager {
                             tokenAddress: tokenAddress,
                             tradeData: data,
                             recommenderId: recommenderId,
+                            username: username,
                         }),
                     }
                 );

From 530e16a25286b57662ecaecba660c767a8879361 Mon Sep 17 00:00:00 2001
From: MarcoMandar <malicemandar@gmail.com>
Date: Wed, 20 Nov 2024 12:28:11 +0200
Subject: [PATCH 03/12] simulation selling service initial

Signed-off-by: MarcoMandar <malicemandar@gmail.com>
---
 .../src/providers/simulationSellingService.ts | 255 ++++++++++++++++++
 .../src/adapters/trustScoreDatabase.ts        |  24 ++
 2 files changed, 279 insertions(+)
 create mode 100644 packages/plugin-solana/src/providers/simulationSellingService.ts

diff --git a/packages/plugin-solana/src/providers/simulationSellingService.ts b/packages/plugin-solana/src/providers/simulationSellingService.ts
new file mode 100644
index 00000000000..fc626592538
--- /dev/null
+++ b/packages/plugin-solana/src/providers/simulationSellingService.ts
@@ -0,0 +1,255 @@
+import {
+    TrustScoreDatabase,
+    TokenPerformance,
+    TradePerformance,
+    TokenRecommendation,
+    ProcessedTokenData,
+} from "@ai16z/plugin-trustdb";
+import { Connection, PublicKey } from "@solana/web3.js";
+// Assuming TokenProvider and IAgentRuntime are available
+import { TokenProvider } from "./token.ts";
+import { settings } from "@ai16z/eliza";
+import { IAgentRuntime, Memory, Provider, State } from "@ai16z/eliza";
+import { WalletProvider } from "./wallet.ts";
+
+interface sellDetails {
+    sell_amount: number;
+    sell_recommender_id: string | null;
+}
+
+export class simulationSellingService {
+    private trustScoreDb: TrustScoreDatabase;
+    private walletProvider: WalletProvider;
+    private connection: Connection;
+    private baseMint: PublicKey;
+    private DECAY_RATE = 0.95;
+    private MAX_DECAY_DAYS = 30;
+    private backend: string;
+    private backendToken: string;
+
+    constructor(
+        runtime: IAgentRuntime,
+        trustScoreDb: TrustScoreDatabase,
+        walletProvider: WalletProvider
+    ) {
+        this.trustScoreDb = trustScoreDb;
+
+        this.connection = new Connection(runtime.getSetting("RPC_URL"));
+        this.walletProvider = new WalletProvider(
+            this.connection,
+            new PublicKey(runtime.getSetting("WALLET_PUBLIC_KEY"))
+        );
+        this.baseMint = new PublicKey(
+            runtime.getSetting("BASE_MINT") ||
+                "So11111111111111111111111111111111111111112"
+        );
+        this.backend = runtime.getSetting("BACKEND_URL");
+        this.backendToken = runtime.getSetting("BACKEND_TOKEN");
+    }
+
+    public async startService() {
+        // starting the service
+        console.log("Starting SellingService...");
+        await this.scanAndSell();
+    }
+
+    private async scanAndSell() {
+        // scanning recommendations and selling
+        console.log("Scanning for token performances...");
+        const tokenPerformances =
+            await this.trustScoreDb.getAllTokenPerformancesWithBalance();
+
+        const sellDecisions = this.decideWhenToSell(tokenPerformances);
+
+        // Execute sells
+        await this.executeSells(sellDecisions);
+
+        // Perform stop loss checks
+        await this.performStopLoss();
+    }
+
+    private decideWhenToSell(
+        tokenPerformances: TokenPerformance[]
+    ): SellDecision[] {
+        //  To Do: logic when to sell and how much
+        console.log("Deciding when to sell and how much...");
+        const decisions: SellDecision[] = [];
+
+        tokenPerformances.forEach((performance) => {
+            const amountToSell = performance.balance * 0.1;
+            decisions.push({ tokenPerformance: performance, amountToSell });
+        });
+
+        return decisions;
+    }
+
+    private async executeSells(decisions: SellDecision[]) {
+        console.log("Executing sell orders...");
+        for (const decision of decisions) {
+            console.log(
+                `Selling ${decision.amountToSell} of token ${decision.tokenPerformance.tokenSymbol}`
+            );
+            // To Do sell logic
+        }
+    }
+
+    private async performStopLoss() {
+        console.log("Performing stop loss checks...");
+        // To Do: Implement stop loss logic
+    }
+
+    async updateSellDetails(
+        tokenAddress: string,
+        recommenderId: string,
+        sellTimeStamp: string,
+        sellDetails: sellDetails,
+        isSimulation: boolean,
+        tokenProvider: TokenProvider
+    ) {
+        // To Do: Change the logic after codex update
+        const recommender =
+            await this.trustScoreDb.getOrCreateRecommenderWithTelegramId(
+                recommenderId
+            );
+        const processedData: ProcessedTokenData =
+            await tokenProvider.getProcessedTokenData();
+        const prices = await this.walletProvider.fetchPrices(null);
+        const solPrice = prices.solana.usd;
+        const sellSol = sellDetails.sell_amount / parseFloat(solPrice);
+        const sell_value_usd =
+            sellDetails.sell_amount * processedData.tradeData.price;
+        const trade = await this.trustScoreDb.getLatestTradePerformance(
+            tokenAddress,
+            recommender.id,
+            isSimulation
+        );
+        const buyTimeStamp = trade.buy_timeStamp;
+        const marketCap =
+            processedData.dexScreenerData.pairs[0]?.marketCap || 0;
+        const liquidity =
+            processedData.dexScreenerData.pairs[0]?.liquidity.usd || 0;
+        const sell_price = processedData.tradeData.price;
+        const profit_usd = sell_value_usd - trade.buy_value_usd;
+        const profit_percent = (profit_usd / trade.buy_value_usd) * 100;
+
+        const market_cap_change = marketCap - trade.buy_market_cap;
+        const liquidity_change = liquidity - trade.buy_liquidity;
+
+        const isRapidDump = await this.isRapidDump(tokenAddress, tokenProvider);
+
+        const sellDetailsData = {
+            sell_price: sell_price,
+            sell_timeStamp: sellTimeStamp,
+            sell_amount: sellDetails.sell_amount,
+            received_sol: sellSol,
+            sell_value_usd: sell_value_usd,
+            profit_usd: profit_usd,
+            profit_percent: profit_percent,
+            sell_market_cap: marketCap,
+            market_cap_change: market_cap_change,
+            sell_liquidity: liquidity,
+            liquidity_change: liquidity_change,
+            rapidDump: isRapidDump,
+            sell_recommender_id: sellDetails.sell_recommender_id || null,
+        };
+        this.trustScoreDb.updateTradePerformanceOnSell(
+            tokenAddress,
+            recommender.id,
+            buyTimeStamp,
+            sellDetailsData,
+            isSimulation
+        );
+
+        // If the trade is a simulation update the balance
+        const oldBalance = this.trustScoreDb.getTokenBalance(tokenAddress);
+        const tokenBalance = oldBalance - sellDetails.sell_amount;
+        this.trustScoreDb.updateTokenBalance(tokenAddress, tokenBalance);
+        // generate some random hash for simulations
+        const hash = Math.random().toString(36).substring(7);
+        const transaction = {
+            tokenAddress: tokenAddress,
+            type: "sell",
+            transactionHash: hash,
+            amount: sellDetails.sell_amount,
+            price: processedData.tradeData.price,
+            isSimulation: true,
+            timestamp: new Date().toISOString(),
+        };
+        this.trustScoreDb.addTransaction(transaction);
+        this.updateTradeInBe(
+            tokenAddress,
+            recommender.id,
+            recommender.telegramId,
+            sellDetailsData,
+            tokenBalance
+        );
+
+        return sellDetailsData;
+    }
+    async isRapidDump(
+        tokenAddress: string,
+        tokenProvider: TokenProvider
+    ): Promise<boolean> {
+        const processedData: ProcessedTokenData =
+            await tokenProvider.getProcessedTokenData();
+        console.log(`Fetched processed token data for token: ${tokenAddress}`);
+
+        return processedData.tradeData.trade_24h_change_percent < -50;
+    }
+
+    async delay(ms: number) {
+        return new Promise((resolve) => setTimeout(resolve, ms));
+    }
+
+    async updateTradeInBe(
+        tokenAddress: string,
+        recommenderId: string,
+        username: string,
+        data: sellDetails,
+        balanceLeft: number,
+        retries = 3,
+        delayMs = 2000
+    ) {
+        for (let attempt = 1; attempt <= retries; attempt++) {
+            try {
+                await fetch(
+                    `${this.backend}/api/updaters/updateTradePerformance`,
+                    {
+                        method: "POST",
+                        headers: {
+                            "Content-Type": "application/json",
+                            Authorization: `Bearer ${this.backendToken}`,
+                        },
+                        body: JSON.stringify({
+                            tokenAddress: tokenAddress,
+                            tradeData: data,
+                            recommenderId: recommenderId,
+                            username: username,
+                            isSimulation: true,
+                            balanceLeft: balanceLeft,
+                        }),
+                    }
+                );
+                // If the request is successful, exit the loop
+                return;
+            } catch (error) {
+                console.error(
+                    `Attempt ${attempt} failed: Error creating trade in backend`,
+                    error
+                );
+                if (attempt < retries) {
+                    console.log(`Retrying in ${delayMs} ms...`);
+                    await this.delay(delayMs); // Wait for the specified delay before retrying
+                } else {
+                    console.error("All attempts failed.");
+                }
+            }
+        }
+    }
+}
+
+// SellDecision interface
+interface SellDecision {
+    tokenPerformance: TokenPerformance;
+    amountToSell: number;
+}
diff --git a/packages/plugin-trustdb/src/adapters/trustScoreDatabase.ts b/packages/plugin-trustdb/src/adapters/trustScoreDatabase.ts
index 5fd6e3d8bb7..302d194d610 100644
--- a/packages/plugin-trustdb/src/adapters/trustScoreDatabase.ts
+++ b/packages/plugin-trustdb/src/adapters/trustScoreDatabase.ts
@@ -827,6 +827,30 @@ export class TrustScoreDatabase {
         };
     }
 
+    getAllTokenPerformancesWithBalance(): TokenPerformance[] {
+        const sql = `SELECT * FROM token_performance WHERE balance > 0;`;
+        const rows = this.db.prepare(sql).all() as TokenPerformanceRow[];
+
+        return rows.map((row) => ({
+            tokenAddress: row.token_address,
+            priceChange24h: row.price_change_24h,
+            volumeChange24h: row.volume_change_24h,
+            trade_24h_change: row.trade_24h_change,
+            liquidity: row.liquidity,
+            liquidityChange24h: row.liquidity_change_24h,
+            holderChange24h: row.holder_change_24h,
+            rugPull: row.rug_pull === 1,
+            isScam: row.is_scam === 1,
+            marketCapChange24h: row.market_cap_change24h,
+            sustainedGrowth: row.sustained_growth === 1,
+            rapidDump: row.rapid_dump === 1,
+            suspiciousVolume: row.suspicious_volume === 1,
+            validationTrust: row.validation_trust,
+            balance: row.balance,
+            lastUpdated: new Date(row.last_updated),
+        }));
+    }
+
     // ----- TokenRecommendations Methods -----
 
     /**

From e6c34560304fd45a235b21d490de0d17a005c6ce Mon Sep 17 00:00:00 2001
From: MarcoMandar <malicemandar@gmail.com>
Date: Thu, 21 Nov 2024 02:27:46 +0200
Subject: [PATCH 04/12] update sell simulation to include stop loss and
 calculate amount to sell

Signed-off-by: MarcoMandar <malicemandar@gmail.com>
---
 .../src/providers/simulationSellingService.ts | 83 +++++++++++++++++--
 1 file changed, 78 insertions(+), 5 deletions(-)

diff --git a/packages/plugin-solana/src/providers/simulationSellingService.ts b/packages/plugin-solana/src/providers/simulationSellingService.ts
index fc626592538..0ab0c76b2b2 100644
--- a/packages/plugin-solana/src/providers/simulationSellingService.ts
+++ b/packages/plugin-solana/src/providers/simulationSellingService.ts
@@ -65,7 +65,7 @@ export class simulationSellingService {
         await this.executeSells(sellDecisions);
 
         // Perform stop loss checks
-        await this.performStopLoss();
+        await this.performStopLoss(tokenPerformances);
     }
 
     private decideWhenToSell(
@@ -75,27 +75,100 @@ export class simulationSellingService {
         console.log("Deciding when to sell and how much...");
         const decisions: SellDecision[] = [];
 
-        tokenPerformances.forEach((performance) => {
-            const amountToSell = performance.balance * 0.1;
+        tokenPerformances.forEach(async (performance) => {
+            const tokenProvider = new TokenProvider(
+                performance.tokenAddress,
+                this.walletProvider
+            );
+            const sellAmount = await this.amountToSell(
+                performance.tokenAddress,
+                tokenProvider
+            );
+            const amountToSell = sellAmount.sellAmount;
             decisions.push({ tokenPerformance: performance, amountToSell });
         });
 
         return decisions;
     }
 
+    async amountToSell(tokenAddress: string, tokenProvider: TokenProvider) {
+        // To Do: Implement logic to decide how much to sell
+        //placeholder
+        const processedData: ProcessedTokenData =
+            await tokenProvider.getProcessedTokenData();
+        const prices = await this.walletProvider.fetchPrices(null);
+        const solPrice = prices.solana.usd;
+        const tokenBalance = this.trustScoreDb.getTokenBalance(tokenAddress);
+
+        const sellAmount = tokenBalance * 0.1;
+        const sellSol = sellAmount / parseFloat(solPrice);
+        const sellValueUsd = sellAmount * processedData.tradeData.price;
+
+        return { sellAmount, sellSol, sellValueUsd };
+    }
+
     private async executeSells(decisions: SellDecision[]) {
         console.log("Executing sell orders...");
         for (const decision of decisions) {
             console.log(
                 `Selling ${decision.amountToSell} of token ${decision.tokenPerformance.tokenSymbol}`
             );
-            // To Do sell logic
+            // update the sell details
+            const sellDetails = {
+                sell_amount: decision.amountToSell,
+                sell_recommender_id: null,
+            };
+            const sellTimeStamp = new Date().toISOString();
+            const tokenProvider = new TokenProvider(
+                decision.tokenPerformance.tokenAddress,
+                this.walletProvider
+            );
+            const sellDetailsData = await this.updateSellDetails(
+                decision.tokenPerformance.tokenAddress,
+                decision.tokenPerformance.recommenderId,
+                sellTimeStamp,
+                sellDetails,
+                true,
+                tokenProvider
+            );
+            console.log("Sell order executed successfully", sellDetailsData);
         }
     }
 
-    private async performStopLoss() {
+    private async performStopLoss(tokenPerformances: TokenPerformance[]) {
         console.log("Performing stop loss checks...");
         // To Do: Implement stop loss logic
+        // check if the token has dropped by more than 50% in the last 24 hours
+        for (const performance of tokenPerformances) {
+            const tokenProvider = new TokenProvider(
+                performance.tokenAddress,
+                this.walletProvider
+            );
+            const processedData: ProcessedTokenData =
+                await tokenProvider.getProcessedTokenData();
+            if (processedData.tradeData.trade_24h_change_percent < -50) {
+                const sellAmount = performance.balance;
+                const sellSol = sellAmount / 100;
+                const sellValueUsd = sellAmount * processedData.tradeData.price;
+                const sellDetails = {
+                    sell_amount: sellAmount,
+                    sell_recommender_id: null,
+                };
+                const sellTimeStamp = new Date().toISOString();
+                const sellDetailsData = await this.updateSellDetails(
+                    performance.tokenAddress,
+                    performance.recommenderId,
+                    sellTimeStamp,
+                    sellDetails,
+                    true,
+                    tokenProvider
+                );
+                console.log(
+                    "Stop loss triggered. Sell order executed successfully",
+                    sellDetailsData
+                );
+            }
+        }
     }
 
     async updateSellDetails(

From e240a1812ac467fd2670f59cd29c01343f3b68f3 Mon Sep 17 00:00:00 2001
From: MarcoMandar <malicemandar@gmail.com>
Date: Fri, 22 Nov 2024 01:31:58 +0200
Subject: [PATCH 05/12] add rabbitMq,  executeSellDecision

Signed-off-by: MarcoMandar <malicemandar@gmail.com>
---
 package.json                                  |   1 +
 .../src/providers/simulationSellingService.ts | 300 ++++++++++++------
 .../src/providers/trustScoreProvider.ts       |  13 +
 pnpm-lock.yaml                                |  39 ++-
 4 files changed, 257 insertions(+), 96 deletions(-)

diff --git a/package.json b/package.json
index 5eccfc6e2fc..2d42e0e9bcd 100644
--- a/package.json
+++ b/package.json
@@ -42,6 +42,7 @@
         "node": ">=22"
     },
     "dependencies": {
+        "amqplib": "^0.10.4",
         "ollama-ai-provider": "^0.16.1",
         "optional": "^0.1.4",
         "sharp": "^0.33.5"
diff --git a/packages/plugin-solana/src/providers/simulationSellingService.ts b/packages/plugin-solana/src/providers/simulationSellingService.ts
index 0ab0c76b2b2..cbfc6c7ce5f 100644
--- a/packages/plugin-solana/src/providers/simulationSellingService.ts
+++ b/packages/plugin-solana/src/providers/simulationSellingService.ts
@@ -11,8 +11,9 @@ import { TokenProvider } from "./token.ts";
 import { settings } from "@ai16z/eliza";
 import { IAgentRuntime, Memory, Provider, State } from "@ai16z/eliza";
 import { WalletProvider } from "./wallet.ts";
+import * as amqp from "amqplib";
 
-interface sellDetails {
+interface SellDetails {
     sell_amount: number;
     sell_recommender_id: string | null;
 }
@@ -26,6 +27,12 @@ export class simulationSellingService {
     private MAX_DECAY_DAYS = 30;
     private backend: string;
     private backendToken: string;
+    private amqpConnection: amqp.Connection;
+    private amqpChannel: amqp.Channel;
+    private sonarBe: string;
+    private sonarBeToken: string;
+
+    private runningProcesses: Set<string> = new Set();
 
     constructor(
         runtime: IAgentRuntime,
@@ -45,129 +52,234 @@ export class simulationSellingService {
         );
         this.backend = runtime.getSetting("BACKEND_URL");
         this.backendToken = runtime.getSetting("BACKEND_TOKEN");
+        this.initializeRabbitMQ(runtime.getSetting("AMQP_URL"));
+        this.sonarBe = runtime.getSetting("SONAR_BE");
+        this.sonarBeToken = runtime.getSetting("SONAR_BE_TOKEN");
     }
-
-    public async startService() {
-        // starting the service
-        console.log("Starting SellingService...");
-        await this.scanAndSell();
+    /**
+     * Initializes the RabbitMQ connection and starts consuming messages.
+     * @param amqpUrl The RabbitMQ server URL.
+     */
+    private async initializeRabbitMQ(amqpUrl: string) {
+        try {
+            this.amqpConnection = await amqp.connect(amqpUrl);
+            this.amqpChannel = await this.amqpConnection.createChannel();
+            console.log("Connected to RabbitMQ");
+            // Start consuming messages
+            this.consumeMessages();
+        } catch (error) {
+            console.error("Failed to connect to RabbitMQ:", error);
+        }
     }
 
-    private async scanAndSell() {
-        // scanning recommendations and selling
-        console.log("Scanning for token performances...");
-        const tokenPerformances =
-            await this.trustScoreDb.getAllTokenPerformancesWithBalance();
-
-        const sellDecisions = this.decideWhenToSell(tokenPerformances);
-
-        // Execute sells
-        await this.executeSells(sellDecisions);
-
-        // Perform stop loss checks
-        await this.performStopLoss(tokenPerformances);
+    /**
+     * Sets up the consumer for the specified RabbitMQ queue.
+     */
+    private async consumeMessages() {
+        const queue = "process_eliza_simulation";
+        await this.amqpChannel.assertQueue(queue, { durable: true });
+        this.amqpChannel.consume(
+            queue,
+            (msg) => {
+                if (msg !== null) {
+                    const content = msg.content.toString();
+                    this.processMessage(content);
+                    this.amqpChannel.ack(msg);
+                }
+            },
+            { noAck: false }
+        );
+        console.log(`Listening for messages on queue: ${queue}`);
     }
 
-    private decideWhenToSell(
-        tokenPerformances: TokenPerformance[]
-    ): SellDecision[] {
-        //  To Do: logic when to sell and how much
-        console.log("Deciding when to sell and how much...");
-        const decisions: SellDecision[] = [];
-
-        tokenPerformances.forEach(async (performance) => {
-            const tokenProvider = new TokenProvider(
-                performance.tokenAddress,
-                this.walletProvider
-            );
-            const sellAmount = await this.amountToSell(
-                performance.tokenAddress,
-                tokenProvider
+    /**
+     * Processes incoming messages from RabbitMQ.
+     * @param message The message content as a string.
+     */
+    private async processMessage(message: string) {
+        try {
+            const { tokenAddress, amount, sell_recommender_id } =
+                JSON.parse(message);
+            console.log(
+                `Received message for token ${tokenAddress} to sell ${amount}`
             );
-            const amountToSell = sellAmount.sellAmount;
-            decisions.push({ tokenPerformance: performance, amountToSell });
-        });
-
-        return decisions;
-    }
 
-    async amountToSell(tokenAddress: string, tokenProvider: TokenProvider) {
-        // To Do: Implement logic to decide how much to sell
-        //placeholder
-        const processedData: ProcessedTokenData =
-            await tokenProvider.getProcessedTokenData();
-        const prices = await this.walletProvider.fetchPrices(null);
-        const solPrice = prices.solana.usd;
-        const tokenBalance = this.trustScoreDb.getTokenBalance(tokenAddress);
+            const decision: SellDecision = {
+                tokenPerformance:
+                    await this.trustScoreDb.getTokenPerformance(tokenAddress),
+                amountToSell: amount,
+                sell_recommender_id: sell_recommender_id,
+            };
 
-        const sellAmount = tokenBalance * 0.1;
-        const sellSol = sellAmount / parseFloat(solPrice);
-        const sellValueUsd = sellAmount * processedData.tradeData.price;
+            // Execute the sell
+            await this.executeSellDecision(decision);
 
-        return { sellAmount, sellSol, sellValueUsd };
+            // Remove from running processes after completion
+            this.runningProcesses.delete(tokenAddress);
+        } catch (error) {
+            console.error("Error processing message:", error);
+        }
     }
 
-    private async executeSells(decisions: SellDecision[]) {
-        console.log("Executing sell orders...");
-        for (const decision of decisions) {
+    /**
+     * Executes a single sell decision.
+     * @param decision The sell decision containing token performance and amount to sell.
+     */
+    private async executeSellDecision(decision: SellDecision) {
+        const { tokenPerformance, amountToSell, sell_recommender_id } =
+            decision;
+        const tokenAddress = tokenPerformance.tokenAddress;
+
+        try {
             console.log(
-                `Selling ${decision.amountToSell} of token ${decision.tokenPerformance.tokenSymbol}`
+                `Executing sell for token ${tokenPerformance.tokenSymbol}: ${amountToSell}`
             );
-            // update the sell details
-            const sellDetails = {
-                sell_amount: decision.amountToSell,
-                sell_recommender_id: null,
+
+            // Update the sell details
+            const sellDetails: SellDetails = {
+                sell_amount: amountToSell,
+                sell_recommender_id: sell_recommender_id, // Adjust if necessary
             };
             const sellTimeStamp = new Date().toISOString();
             const tokenProvider = new TokenProvider(
-                decision.tokenPerformance.tokenAddress,
+                tokenAddress,
                 this.walletProvider
             );
+
+            // Update sell details in the database
             const sellDetailsData = await this.updateSellDetails(
-                decision.tokenPerformance.tokenAddress,
-                decision.tokenPerformance.recommenderId,
+                tokenAddress,
+                tokenPerformance.recommenderId,
                 sellTimeStamp,
                 sellDetails,
-                true,
+                true, // isSimulation
                 tokenProvider
             );
+
             console.log("Sell order executed successfully", sellDetailsData);
+
+            // check if balance is zero and remove token from running processes
+            const balance = this.trustScoreDb.getTokenBalance(tokenAddress);
+            if (balance === 0) {
+                this.runningProcesses.delete(tokenAddress);
+            }
+            // stop the process in the sonar backend
+            await this.stopProcessInTheSonarBackend(tokenAddress);
+        } catch (error) {
+            console.error(
+                `Error executing sell for token ${tokenAddress}:`,
+                error
+            );
         }
     }
 
-    private async performStopLoss(tokenPerformances: TokenPerformance[]) {
-        console.log("Performing stop loss checks...");
-        // To Do: Implement stop loss logic
-        // check if the token has dropped by more than 50% in the last 24 hours
-        for (const performance of tokenPerformances) {
+    public async startService() {
+        // starting the service
+        console.log("Starting SellingService...");
+        await this.startListeners();
+    }
+
+    private async startListeners() {
+        // scanning recommendations and selling
+        console.log("Scanning for token performances...");
+        const tokenPerformances =
+            await this.trustScoreDb.getAllTokenPerformancesWithBalance();
+
+        await this.processTokenPerformances(tokenPerformances);
+    }
+
+    private processTokenPerformances(tokenPerformances: TokenPerformance[]) {
+        //  To Do: logic when to sell and how much
+        console.log("Deciding when to sell and how much...");
+        const runningProcesses = this.runningProcesses;
+        // remove running processes from tokenPerformances
+        tokenPerformances = tokenPerformances.filter(
+            (tp) => !runningProcesses.has(tp.tokenAddress)
+        );
+
+        // start the process in the sonar backend
+        tokenPerformances.forEach(async (tokenPerformance) => {
             const tokenProvider = new TokenProvider(
-                performance.tokenAddress,
+                tokenPerformance.tokenAddress,
                 this.walletProvider
             );
-            const processedData: ProcessedTokenData =
-                await tokenProvider.getProcessedTokenData();
-            if (processedData.tradeData.trade_24h_change_percent < -50) {
-                const sellAmount = performance.balance;
-                const sellSol = sellAmount / 100;
-                const sellValueUsd = sellAmount * processedData.tradeData.price;
-                const sellDetails = {
-                    sell_amount: sellAmount,
-                    sell_recommender_id: null,
-                };
-                const sellTimeStamp = new Date().toISOString();
-                const sellDetailsData = await this.updateSellDetails(
-                    performance.tokenAddress,
-                    performance.recommenderId,
-                    sellTimeStamp,
-                    sellDetails,
-                    true,
-                    tokenProvider
+            const shouldTrade = await tokenProvider.shouldTradeToken();
+            if (shouldTrade) {
+                const balance = tokenPerformance.balance;
+                const sell_recommender_id = tokenPerformance.recommenderId;
+                const tokenAddress = tokenPerformance.tokenAddress;
+                const process = await this.startProcessInTheSonarBackend(
+                    tokenAddress,
+                    balance,
+                    sell_recommender_id
                 );
-                console.log(
-                    "Stop loss triggered. Sell order executed successfully",
-                    sellDetailsData
+                if (process) {
+                    this.runningProcesses.add(tokenAddress);
+                }
+            }
+        });
+    }
+
+    private async startProcessInTheSonarBackend(
+        tokenAddress: string,
+        balance: number,
+        sell_recommender_id: string
+    ) {
+        try {
+            const message = JSON.stringify({
+                tokenAddress,
+                balance,
+                sell_recommender_id,
+            });
+            const response = await fetch(
+                `${this.sonarBe}/api/simulation/sell`,
+                {
+                    method: "POST",
+                    headers: {
+                        "Content-Type": "application/json",
+                        Authorization: `Bearer ${this.sonarBeToken}`,
+                    },
+                    body: message,
+                }
+            );
+
+            if (!response.ok) {
+                console.error(
+                    `Failed to send message to process token ${tokenAddress}`
                 );
+                return;
             }
+
+            const result = await response.json();
+            console.log("Received response:", result);
+            console.log(`Sent message to process token ${tokenAddress}`);
+
+            return result;
+        } catch (error) {
+            console.error(
+                `Error sending message to process token ${tokenAddress}:`,
+                error
+            );
+            return null;
+        }
+    }
+
+    private stopProcessInTheSonarBackend(tokenAddress: string) {
+        try {
+            return fetch(
+                `${this.sonarBe}/api/simulation/sell/${tokenAddress}`,
+                {
+                    method: "GET",
+                    headers: {
+                        Authorization: `Bearer ${this.sonarBeToken}`,
+                    },
+                }
+            );
+        } catch (error) {
+            console.error(
+                `Error stopping process for token ${tokenAddress}:`,
+                error
+            );
         }
     }
 
@@ -175,11 +287,10 @@ export class simulationSellingService {
         tokenAddress: string,
         recommenderId: string,
         sellTimeStamp: string,
-        sellDetails: sellDetails,
+        sellDetails: SellDetails,
         isSimulation: boolean,
         tokenProvider: TokenProvider
     ) {
-        // To Do: Change the logic after codex update
         const recommender =
             await this.trustScoreDb.getOrCreateRecommenderWithTelegramId(
                 recommenderId
@@ -278,7 +389,7 @@ export class simulationSellingService {
         tokenAddress: string,
         recommenderId: string,
         username: string,
-        data: sellDetails,
+        data: SellDetails,
         balanceLeft: number,
         retries = 3,
         delayMs = 2000
@@ -325,4 +436,5 @@ export class simulationSellingService {
 interface SellDecision {
     tokenPerformance: TokenPerformance;
     amountToSell: number;
+    sell_recommender_id: string | null;
 }
diff --git a/packages/plugin-solana/src/providers/trustScoreProvider.ts b/packages/plugin-solana/src/providers/trustScoreProvider.ts
index 4478e2c94b6..7e05dfa57e0 100644
--- a/packages/plugin-solana/src/providers/trustScoreProvider.ts
+++ b/packages/plugin-solana/src/providers/trustScoreProvider.ts
@@ -389,6 +389,19 @@ export class TrustScoreManager {
         };
         this.trustScoreDb.addTradePerformance(creationData, data.is_simulation);
 
+        const tokenRecommendation: TokenRecommendation = {
+            recommenderId: recommenderId,
+            tokenAddress: tokenAddress,
+            timestamp: new Date(),
+            initialMarketCap:
+                processedData.dexScreenerData.pairs[0]?.marketCap || 0,
+            initialLiquidity:
+                processedData.dexScreenerData.pairs[0]?.liquidity || 0,
+            initialPrice: processedData.tradeData.price,
+        };
+
+        this.trustScoreDb.addTokenRecommendation(tokenRecommendation);
+
         if (data.is_simulation) {
             // If the trade is a simulation update the balance
             this.trustScoreDb.updateTokenBalance(tokenAddress, tokensBalance);
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index f85cfec055d..37c212913a1 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -11,6 +11,9 @@ importers:
 
   .:
     dependencies:
+      amqplib:
+        specifier: ^0.10.4
+        version: 0.10.4
       ollama-ai-provider:
         specifier: ^0.16.1
         version: 0.16.1(zod@3.23.8)
@@ -621,7 +624,7 @@ importers:
         version: 2.79.2
       ts-jest:
         specifier: 29.2.5
-        version: 29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)))(typescript@5.6.3)
+        version: 29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(esbuild@0.24.0)(jest@29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)))(typescript@5.6.3)
       ts-node:
         specifier: 10.9.2
         version: 10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)
@@ -933,6 +936,10 @@ importers:
 
 packages:
 
+  '@acuminous/bitsyntax@0.1.2':
+    resolution: {integrity: sha512-29lUK80d1muEQqiUsSo+3A0yP6CdspgC95EnKBMi22Xlwt79i/En4Vr67+cXhU+cZjbti3TgGGC5wy1stIywVQ==}
+    engines: {node: '>=0.8'}
+
   '@adraffy/ens-normalize@1.10.1':
     resolution: {integrity: sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==}
 
@@ -2226,6 +2233,7 @@ packages:
     resolution: {integrity: sha512-hArn9FF5ZYi1IkxdJEVnJi+OxlwLV0NJYWpKXsmNOojtGtAZHxmsELA+MZlu2KW1F/K1/nt7lFOfcMXNYweq9w==}
     version: 0.17.0
     engines: {node: '>=16.11.0'}
+    deprecated: This version uses deprecated encryption modes. Please use a newer version.
 
   '@discordjs/ws@1.1.1':
     resolution: {integrity: sha512-PZ+vLpxGCRtmr2RMkqh8Zp+BenUaJqlS6xhgWKEZcgC/vfHLEzpHtKkB0sl3nZWpwtcKk6YWy+pU3okL2I97FA==}
@@ -5061,6 +5069,10 @@ packages:
   amp@0.3.1:
     resolution: {integrity: sha512-OwIuC4yZaRogHKiuU5WlMR5Xk/jAcpPtawWL05Gj8Lvm2F6mwoJt4O/bHI+DHwG79vWd+8OFYM4/BzYqyRd3qw==}
 
+  amqplib@0.10.4:
+    resolution: {integrity: sha512-DMZ4eCEjAVdX1II2TfIUpJhfKAuoCeDIo/YyETbfAqehHTXxxs7WOOd+N1Xxr4cKhx12y23zk8/os98FxlZHrw==}
+    engines: {node: '>=10'}
+
   ansi-align@3.0.1:
     resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==}
 
@@ -5476,6 +5488,9 @@ packages:
     resolution: {integrity: sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA==}
     engines: {node: '>=4.5'}
 
+  buffer-more-ints@1.0.0:
+    resolution: {integrity: sha512-EMetuGFz5SLsT0QTnXzINh4Ksr+oo4i+UGTXEshiGCQWnsgSs7ZhJ8fzlwQ+OzEMs0MpDAMr1hxnblp5a4vcHg==}
+
   buffer@5.7.1:
     resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
 
@@ -12977,6 +12992,14 @@ packages:
 
 snapshots:
 
+  '@acuminous/bitsyntax@0.1.2':
+    dependencies:
+      buffer-more-ints: 1.0.0
+      debug: 4.3.7(supports-color@5.5.0)
+      safe-buffer: 5.1.2
+    transitivePeerDependencies:
+      - supports-color
+
   '@adraffy/ens-normalize@1.10.1': {}
 
   '@ai-sdk/anthropic@0.0.53(zod@3.23.8)':
@@ -18544,6 +18567,15 @@ snapshots:
 
   amp@0.3.1: {}
 
+  amqplib@0.10.4:
+    dependencies:
+      '@acuminous/bitsyntax': 0.1.2
+      buffer-more-ints: 1.0.0
+      readable-stream: 1.1.14
+      url-parse: 1.5.10
+    transitivePeerDependencies:
+      - supports-color
+
   ansi-align@3.0.1:
     dependencies:
       string-width: 4.2.3
@@ -19001,6 +19033,8 @@ snapshots:
 
   buffer-layout@1.2.2: {}
 
+  buffer-more-ints@1.0.0: {}
+
   buffer@5.7.1:
     dependencies:
       base64-js: 1.5.1
@@ -27140,7 +27174,7 @@ snapshots:
 
   ts-interface-checker@0.1.13: {}
 
-  ts-jest@29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)))(typescript@5.6.3):
+  ts-jest@29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(esbuild@0.24.0)(jest@29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)))(typescript@5.6.3):
     dependencies:
       bs-logger: 0.2.6
       ejs: 3.1.10
@@ -27158,6 +27192,7 @@ snapshots:
       '@jest/transform': 29.7.0
       '@jest/types': 29.6.3
       babel-jest: 29.7.0(@babel/core@7.26.0)
+      esbuild: 0.24.0
 
   ts-mixer@6.0.4: {}
 

From 6d6296ebf8a496ccf563a0561acdc662e082b257 Mon Sep 17 00:00:00 2001
From: MarcoMandar <malicemandar@gmail.com>
Date: Mon, 25 Nov 2024 23:20:12 +0200
Subject: [PATCH 06/12] updates for the backend

Signed-off-by: MarcoMandar <malicemandar@gmail.com>
---
 .../src/providers/simulationSellingService.ts | 30 ++++++++++---------
 .../src/providers/trustScoreProvider.ts       | 24 ++++++++++++++-
 .../src/adapters/trustScoreDatabase.ts        | 20 +++++++++++++
 3 files changed, 59 insertions(+), 15 deletions(-)

diff --git a/packages/plugin-solana/src/providers/simulationSellingService.ts b/packages/plugin-solana/src/providers/simulationSellingService.ts
index cbfc6c7ce5f..d3d7ce267d3 100644
--- a/packages/plugin-solana/src/providers/simulationSellingService.ts
+++ b/packages/plugin-solana/src/providers/simulationSellingService.ts
@@ -211,7 +211,8 @@ export class simulationSellingService {
                 const process = await this.startProcessInTheSonarBackend(
                     tokenAddress,
                     balance,
-                    sell_recommender_id
+                    sell_recommender_id,
+                    tokenPerformance.initial_mc
                 );
                 if (process) {
                     this.runningProcesses.add(tokenAddress);
@@ -223,21 +224,23 @@ export class simulationSellingService {
     private async startProcessInTheSonarBackend(
         tokenAddress: string,
         balance: number,
-        sell_recommender_id: string
+        isSimulation: boolean,
+        initial_mc: number
     ) {
         try {
             const message = JSON.stringify({
                 tokenAddress,
                 balance,
-                sell_recommender_id,
+                isSimulation,
+                initial_mc,
             });
             const response = await fetch(
-                `${this.sonarBe}/api/simulation/sell`,
+                `${this.sonarBe}/ai16z-sol/startProcess`,
                 {
                     method: "POST",
                     headers: {
                         "Content-Type": "application/json",
-                        Authorization: `Bearer ${this.sonarBeToken}`,
+                        "x-api-key": `${this.sonarBeToken}`,
                     },
                     body: message,
                 }
@@ -266,15 +269,14 @@ export class simulationSellingService {
 
     private stopProcessInTheSonarBackend(tokenAddress: string) {
         try {
-            return fetch(
-                `${this.sonarBe}/api/simulation/sell/${tokenAddress}`,
-                {
-                    method: "GET",
-                    headers: {
-                        Authorization: `Bearer ${this.sonarBeToken}`,
-                    },
-                }
-            );
+            return fetch(`${this.sonarBe}/ai16z-sol/stopProcess`, {
+                method: "POST",
+                headers: {
+                    "Content-Type": "application/json",
+                    "x-api-key": `${this.sonarBeToken}`,
+                },
+                body: JSON.stringify({ tokenAddress }),
+            });
         } catch (error) {
             console.error(
                 `Error stopping process for token ${tokenAddress}:`,
diff --git a/packages/plugin-solana/src/providers/trustScoreProvider.ts b/packages/plugin-solana/src/providers/trustScoreProvider.ts
index 7e05dfa57e0..73ba858baef 100644
--- a/packages/plugin-solana/src/providers/trustScoreProvider.ts
+++ b/packages/plugin-solana/src/providers/trustScoreProvider.ts
@@ -399,9 +399,31 @@ export class TrustScoreManager {
                 processedData.dexScreenerData.pairs[0]?.liquidity || 0,
             initialPrice: processedData.tradeData.price,
         };
-
         this.trustScoreDb.addTokenRecommendation(tokenRecommendation);
 
+        this.trustScoreDb.upsertTokenPerformance({
+            tokenAddress: tokenAddress,
+            priceChange24h: processedData.tradeData.price_change_24h_percent,
+            volumeChange24h: processedData.tradeData.volume_24h,
+            trade_24h_change: processedData.tradeData.trade_24h_change_percent,
+            liquidity:
+                processedData.dexScreenerData.pairs[0]?.liquidity.usd || 0,
+            liquidityChange24h: 0,
+            holderChange24h:
+                processedData.tradeData.unique_wallet_24h_change_percent,
+            rugPull: false,
+            isScam: false,
+            marketCapChange24h: 0,
+            sustainedGrowth: false,
+            rapidDump: false,
+            suspiciousVolume: false,
+            validationTrust: 0,
+            balance: tokensBalance,
+            initialMarketCap:
+                processedData.dexScreenerData.pairs[0]?.marketCap || 0,
+            lastUpdated: new Date(),
+        });
+
         if (data.is_simulation) {
             // If the trade is a simulation update the balance
             this.trustScoreDb.updateTokenBalance(tokenAddress, tokensBalance);
diff --git a/packages/plugin-trustdb/src/adapters/trustScoreDatabase.ts b/packages/plugin-trustdb/src/adapters/trustScoreDatabase.ts
index 302d194d610..b877d52e8b5 100644
--- a/packages/plugin-trustdb/src/adapters/trustScoreDatabase.ts
+++ b/packages/plugin-trustdb/src/adapters/trustScoreDatabase.ts
@@ -41,6 +41,7 @@ export interface TokenPerformance {
     suspiciousVolume: boolean;
     validationTrust: number;
     balance: number;
+    initialMarketCap: number;
     lastUpdated: Date;
 }
 
@@ -122,6 +123,7 @@ interface TokenPerformanceRow {
     suspicious_volume: number;
     validation_trust: number;
     balance: number;
+    initial_market_cap: number;
     last_updated: string;
 }
 
@@ -205,6 +207,7 @@ export class TrustScoreDatabase {
                 suspicious_volume BOOLEAN DEFAULT FALSE,
                 validation_trust REAL DEFAULT 0,
                 balance REAL DEFAULT 0,
+                initial_market_cap REAL DEFAULT 0,
                 last_updated DATETIME DEFAULT CURRENT_TIMESTAMP
             );
         `);
@@ -731,6 +734,8 @@ export class TrustScoreDatabase {
                 rapid_dump,
                 suspicious_volume,
                 validation_trust,
+                balance,
+                initial_market_cap,
                 last_updated
             ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
             ON CONFLICT(token_address) DO UPDATE SET
@@ -747,6 +752,8 @@ export class TrustScoreDatabase {
                 rapid_dump = excluded.rapid_dump,
                 suspicious_volume = excluded.suspicious_volume,
                 validation_trust = excluded.validation_trust,
+                balance = excluded.balance,
+                initial_market_cap = excluded.initial_market_cap,
                 last_updated = CURRENT_TIMESTAMP;
         `;
         try {
@@ -764,6 +771,8 @@ export class TrustScoreDatabase {
                 performance.sustainedGrowth ? 1 : 0,
                 performance.rapidDump ? 1 : 0,
                 performance.suspiciousVolume ? 1 : 0,
+                performance.balance,
+                performance.initialMarketCap,
                 validationTrust
             );
             console.log(
@@ -823,10 +832,20 @@ export class TrustScoreDatabase {
             suspiciousVolume: row.suspicious_volume === 1,
             validationTrust: row.validation_trust,
             balance: row.balance,
+            initialMarketCap: row.initial_market_cap,
             lastUpdated: new Date(row.last_updated),
         };
     }
 
+    //getTokenBalance
+    getTokenBalance(tokenAddress: string): number {
+        const sql = `SELECT balance FROM token_performance WHERE token_address = ?;`;
+        const row = this.db.prepare(sql).get(tokenAddress) as {
+            balance: number;
+        };
+        return row.balance;
+    }
+
     getAllTokenPerformancesWithBalance(): TokenPerformance[] {
         const sql = `SELECT * FROM token_performance WHERE balance > 0;`;
         const rows = this.db.prepare(sql).all() as TokenPerformanceRow[];
@@ -847,6 +866,7 @@ export class TrustScoreDatabase {
             suspiciousVolume: row.suspicious_volume === 1,
             validationTrust: row.validation_trust,
             balance: row.balance,
+            initialMarketCap: row.initial_market_cap,
             lastUpdated: new Date(row.last_updated),
         }));
     }

From 0b029c0d397facbe48b37c73af6acff411a27449 Mon Sep 17 00:00:00 2001
From: MarcoMandar <malicemandar@gmail.com>
Date: Mon, 25 Nov 2024 23:41:49 +0200
Subject: [PATCH 07/12] sell simulation service

Signed-off-by: MarcoMandar <malicemandar@gmail.com>
---
 .../src/providers/simulationSellingService.ts      | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/packages/plugin-solana/src/providers/simulationSellingService.ts b/packages/plugin-solana/src/providers/simulationSellingService.ts
index d3d7ce267d3..8e841455b7f 100644
--- a/packages/plugin-solana/src/providers/simulationSellingService.ts
+++ b/packages/plugin-solana/src/providers/simulationSellingService.ts
@@ -1,14 +1,14 @@
 import {
     TrustScoreDatabase,
     TokenPerformance,
-    TradePerformance,
-    TokenRecommendation,
+    // TradePerformance,
+    // TokenRecommendation,
     ProcessedTokenData,
 } from "@ai16z/plugin-trustdb";
 import { Connection, PublicKey } from "@solana/web3.js";
 // Assuming TokenProvider and IAgentRuntime are available
 import { TokenProvider } from "./token.ts";
-import { settings } from "@ai16z/eliza";
+// import { settings } from "@ai16z/eliza";
 import { IAgentRuntime, Memory, Provider, State } from "@ai16z/eliza";
 import { WalletProvider } from "./wallet.ts";
 import * as amqp from "amqplib";
@@ -31,6 +31,7 @@ export class simulationSellingService {
     private amqpChannel: amqp.Channel;
     private sonarBe: string;
     private sonarBeToken: string;
+    private runtime: IAgentRuntime;
 
     private runningProcesses: Set<string> = new Set();
 
@@ -55,6 +56,7 @@ export class simulationSellingService {
         this.initializeRabbitMQ(runtime.getSetting("AMQP_URL"));
         this.sonarBe = runtime.getSetting("SONAR_BE");
         this.sonarBeToken = runtime.getSetting("SONAR_BE_TOKEN");
+        this.runtime = runtime;
     }
     /**
      * Initializes the RabbitMQ connection and starts consuming messages.
@@ -143,7 +145,8 @@ export class simulationSellingService {
             const sellTimeStamp = new Date().toISOString();
             const tokenProvider = new TokenProvider(
                 tokenAddress,
-                this.walletProvider
+                this.walletProvider,
+                this.runtime.cacheManager
             );
 
             // Update sell details in the database
@@ -201,7 +204,8 @@ export class simulationSellingService {
         tokenPerformances.forEach(async (tokenPerformance) => {
             const tokenProvider = new TokenProvider(
                 tokenPerformance.tokenAddress,
-                this.walletProvider
+                this.walletProvider,
+                this.runtime.cacheManager
             );
             const shouldTrade = await tokenProvider.shouldTradeToken();
             if (shouldTrade) {

From e2a894f86ebbe1fc084f9ea8458b055a51df7bba Mon Sep 17 00:00:00 2001
From: MarcoMandar <malicemandar@gmail.com>
Date: Mon, 25 Nov 2024 23:43:21 +0200
Subject: [PATCH 08/12] walletProvider

Signed-off-by: MarcoMandar <malicemandar@gmail.com>
---
 .../plugin-solana/src/providers/simulationSellingService.ts | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/packages/plugin-solana/src/providers/simulationSellingService.ts b/packages/plugin-solana/src/providers/simulationSellingService.ts
index 8e841455b7f..937b29765d1 100644
--- a/packages/plugin-solana/src/providers/simulationSellingService.ts
+++ b/packages/plugin-solana/src/providers/simulationSellingService.ts
@@ -35,11 +35,7 @@ export class simulationSellingService {
 
     private runningProcesses: Set<string> = new Set();
 
-    constructor(
-        runtime: IAgentRuntime,
-        trustScoreDb: TrustScoreDatabase,
-        walletProvider: WalletProvider
-    ) {
+    constructor(runtime: IAgentRuntime, trustScoreDb: TrustScoreDatabase) {
         this.trustScoreDb = trustScoreDb;
 
         this.connection = new Connection(runtime.getSetting("RPC_URL"));

From 5877e42fef044e50e15e1e68d9bc1a855dbf0e4f Mon Sep 17 00:00:00 2001
From: MarcoMandar <malicemandar@gmail.com>
Date: Mon, 25 Nov 2024 23:50:23 +0200
Subject: [PATCH 09/12] fix no-unused-vars

Signed-off-by: MarcoMandar <malicemandar@gmail.com>
---
 .../plugin-solana/src/providers/simulationSellingService.ts     | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/plugin-solana/src/providers/simulationSellingService.ts b/packages/plugin-solana/src/providers/simulationSellingService.ts
index 937b29765d1..20c92fb60f3 100644
--- a/packages/plugin-solana/src/providers/simulationSellingService.ts
+++ b/packages/plugin-solana/src/providers/simulationSellingService.ts
@@ -9,7 +9,7 @@ import { Connection, PublicKey } from "@solana/web3.js";
 // Assuming TokenProvider and IAgentRuntime are available
 import { TokenProvider } from "./token.ts";
 // import { settings } from "@ai16z/eliza";
-import { IAgentRuntime, Memory, Provider, State } from "@ai16z/eliza";
+import { IAgentRuntime } from "@ai16z/eliza";
 import { WalletProvider } from "./wallet.ts";
 import * as amqp from "amqplib";
 

From 2d93baaf9bf68b14277363a6e2afceb45bba6178 Mon Sep 17 00:00:00 2001
From: MarcoMandar <malicemandar@gmail.com>
Date: Mon, 25 Nov 2024 23:58:36 +0200
Subject: [PATCH 10/12] trustscore updates

Signed-off-by: MarcoMandar <malicemandar@gmail.com>
---
 .../src/providers/trustScoreProvider.ts       |   9 +-
 pnpm-lock.yaml                                | 386 ++++++++++++++----
 2 files changed, 303 insertions(+), 92 deletions(-)

diff --git a/packages/plugin-solana/src/providers/trustScoreProvider.ts b/packages/plugin-solana/src/providers/trustScoreProvider.ts
index 1d9c0939801..394fb32387e 100644
--- a/packages/plugin-solana/src/providers/trustScoreProvider.ts
+++ b/packages/plugin-solana/src/providers/trustScoreProvider.ts
@@ -153,6 +153,9 @@ export class TrustScoreManager {
                 rapidDump: isRapidDump,
                 suspiciousVolume: suspiciousVolume,
                 validationTrust: validationTrustScore,
+                balance: balance,
+                initialMarketCap:
+                    processedData.dexScreenerData.pairs[0]?.marketCap || 0,
                 lastUpdated: new Date(),
             },
             recommenderMetrics: {
@@ -396,7 +399,7 @@ export class TrustScoreManager {
             initialMarketCap:
                 processedData.dexScreenerData.pairs[0]?.marketCap || 0,
             initialLiquidity:
-                processedData.dexScreenerData.pairs[0]?.liquidity || 0,
+                processedData.dexScreenerData.pairs[0]?.liquidity?.usd || 0,
             initialPrice: processedData.tradeData.price,
         };
         this.trustScoreDb.addTokenRecommendation(tokenRecommendation);
@@ -431,7 +434,7 @@ export class TrustScoreManager {
             const hash = Math.random().toString(36).substring(7);
             const transaction = {
                 tokenAddress: tokenAddress,
-                type: "buy",
+                type: "buy" as "buy" | "sell",
                 transactionHash: hash,
                 amount: data.buy_amount,
                 price: processedData.tradeData.price,
@@ -575,7 +578,7 @@ export class TrustScoreManager {
             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/pnpm-lock.yaml b/pnpm-lock.yaml
index e8a3d8a76dd..e4c1f99a495 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -17,12 +17,12 @@ importers:
       '@coinbase/coinbase-sdk':
         specifier: ^0.10.0
         version: 0.10.0(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8)
-      csv-parse:
-        specifier: ^5.6.0
-        version: 5.6.0
       amqplib:
         specifier: ^0.10.4
         version: 0.10.4
+      csv-parse:
+        specifier: ^5.6.0
+        version: 5.6.0
       ollama-ai-provider:
         specifier: ^0.16.1
         version: 0.16.1(zod@3.23.8)
@@ -234,67 +234,6 @@ importers:
         specifier: link:@tanstack/router-plugin/vite
         version: link:@tanstack/router-plugin/vite
 
-  apps/agent:
-    dependencies:
-      '@ai16z/adapter-postgres':
-        specifier: workspace:*
-        version: link:../../packages/adapter-postgres
-      '@ai16z/adapter-sqlite':
-        specifier: workspace:*
-        version: link:../../packages/adapter-sqlite
-      '@ai16z/client-auto':
-        specifier: workspace:*
-        version: link:../../packages/client-auto
-      '@ai16z/client-direct':
-        specifier: workspace:*
-        version: link:../../packages/client-direct
-      '@ai16z/client-discord':
-        specifier: workspace:*
-        version: link:../../packages/client-discord
-      '@ai16z/client-farcaster':
-        specifier: workspace:*
-        version: link:../../packages/client-farcaster
-      '@ai16z/client-telegram':
-        specifier: workspace:*
-        version: link:../../packages/client-telegram
-      '@ai16z/client-twitter':
-        specifier: workspace:*
-        version: link:../../packages/client-twitter
-      '@ai16z/eliza':
-        specifier: workspace:*
-        version: link:../../packages/core
-      '@ai16z/plugin-bootstrap':
-        specifier: workspace:*
-        version: link:../../packages/plugin-bootstrap
-      '@ai16z/plugin-image-generation':
-        specifier: workspace:*
-        version: link:../../packages/plugin-image-generation
-      '@ai16z/plugin-node':
-        specifier: workspace:*
-        version: link:../../packages/plugin-node
-      '@ai16z/plugin-solana':
-        specifier: workspace:*
-        version: link:../../packages/plugin-solana
-      readline:
-        specifier: ^1.3.0
-        version: 1.3.0
-      viem:
-        specifier: ^2.21.47
-        version: 2.21.47(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8)
-      ws:
-        specifier: ^8.18.0
-        version: 8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)
-      yargs:
-        specifier: 17.7.2
-        version: 17.7.2
-    devDependencies:
-      ts-node:
-        specifier: 10.9.2
-        version: 10.9.2(@types/node@22.8.4)(typescript@5.6.3)
-      tsup:
-        specifier: ^8.3.5
-        version: 8.3.5(jiti@1.21.6)(postcss@8.4.47)(typescript@5.6.3)(yaml@2.6.0)
-
   docs:
     dependencies:
       '@docusaurus/core':
@@ -376,7 +315,7 @@ importers:
         version: 5.2.1(@types/eslint@9.6.1)(eslint-config-prettier@9.1.0(eslint@9.13.0(jiti@2.4.0)))(eslint@9.13.0(jiti@2.4.0))(prettier@3.3.3)
       eslint-plugin-vitest:
         specifier: 0.5.4
-        version: 0.5.4(@typescript-eslint/eslint-plugin@8.12.2(@typescript-eslint/parser@8.12.2(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0))
+        version: 0.5.4(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0))
       tsup:
         specifier: 8.3.5
         version: 8.3.5(@swc/core@1.9.3(@swc/helpers@0.5.15))(jiti@2.4.0)(postcss@8.4.49)(typescript@5.6.3)(yaml@2.6.1)
@@ -410,7 +349,7 @@ importers:
         version: 5.2.1(@types/eslint@9.6.1)(eslint-config-prettier@9.1.0(eslint@9.13.0(jiti@2.4.0)))(eslint@9.13.0(jiti@2.4.0))(prettier@3.3.3)
       eslint-plugin-vitest:
         specifier: 0.5.4
-        version: 0.5.4(@typescript-eslint/eslint-plugin@8.12.2(@typescript-eslint/parser@8.12.2(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0))
+        version: 0.5.4(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0))
       tsup:
         specifier: 8.3.5
         version: 8.3.5(@swc/core@1.9.3(@swc/helpers@0.5.15))(jiti@2.4.0)(postcss@8.4.49)(typescript@5.6.3)(yaml@2.6.1)
@@ -444,7 +383,7 @@ importers:
         version: 5.2.1(@types/eslint@9.6.1)(eslint-config-prettier@9.1.0(eslint@9.13.0(jiti@2.4.0)))(eslint@9.13.0(jiti@2.4.0))(prettier@3.3.3)
       eslint-plugin-vitest:
         specifier: 0.5.4
-        version: 0.5.4(@typescript-eslint/eslint-plugin@8.12.2(@typescript-eslint/parser@8.12.2(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0))
+        version: 0.5.4(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0))
       tsup:
         specifier: 8.3.5
         version: 8.3.5(@swc/core@1.9.3(@swc/helpers@0.5.15))(jiti@2.4.0)(postcss@8.4.49)(typescript@5.6.3)(yaml@2.6.1)
@@ -472,7 +411,7 @@ importers:
         version: 5.2.1(@types/eslint@9.6.1)(eslint-config-prettier@9.1.0(eslint@9.13.0(jiti@2.4.0)))(eslint@9.13.0(jiti@2.4.0))(prettier@3.3.3)
       eslint-plugin-vitest:
         specifier: 0.5.4
-        version: 0.5.4(@typescript-eslint/eslint-plugin@8.12.2(@typescript-eslint/parser@8.12.2(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0))
+        version: 0.5.4(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0))
       tsup:
         specifier: 8.3.5
         version: 8.3.5(@swc/core@1.9.3(@swc/helpers@0.5.15))(jiti@2.4.0)(postcss@8.4.49)(typescript@5.6.3)(yaml@2.6.1)
@@ -524,7 +463,7 @@ importers:
         version: 5.2.1(@types/eslint@9.6.1)(eslint-config-prettier@9.1.0(eslint@9.13.0(jiti@2.4.0)))(eslint@9.13.0(jiti@2.4.0))(prettier@3.3.3)
       eslint-plugin-vitest:
         specifier: 0.5.4
-        version: 0.5.4(@typescript-eslint/eslint-plugin@8.12.2(@typescript-eslint/parser@8.12.2(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0))
+        version: 0.5.4(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0))
       tsup:
         specifier: 8.3.5
         version: 8.3.5(@swc/core@1.9.3(@swc/helpers@0.5.15))(jiti@2.4.0)(postcss@8.4.49)(typescript@5.6.3)(yaml@2.6.1)
@@ -576,7 +515,7 @@ importers:
         version: 5.2.1(@types/eslint@9.6.1)(eslint-config-prettier@9.1.0(eslint@9.13.0(jiti@2.4.0)))(eslint@9.13.0(jiti@2.4.0))(prettier@3.3.3)
       eslint-plugin-vitest:
         specifier: 0.5.4
-        version: 0.5.4(@typescript-eslint/eslint-plugin@8.12.2(@typescript-eslint/parser@8.12.2(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0))
+        version: 0.5.4(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0))
       tsup:
         specifier: 8.3.5
         version: 8.3.5(@swc/core@1.9.3(@swc/helpers@0.5.15))(jiti@2.4.0)(postcss@8.4.49)(typescript@5.6.3)(yaml@2.6.1)
@@ -625,11 +564,27 @@ importers:
         version: 5.2.1(@types/eslint@9.6.1)(eslint-config-prettier@9.1.0(eslint@9.13.0(jiti@2.4.0)))(eslint@9.13.0(jiti@2.4.0))(prettier@3.3.3)
       eslint-plugin-vitest:
         specifier: 0.5.4
-        version: 0.5.4(@typescript-eslint/eslint-plugin@8.12.2(@typescript-eslint/parser@8.12.2(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0))
+        version: 0.5.4(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0))
       tsup:
         specifier: 8.3.5
         version: 8.3.5(@swc/core@1.9.3(@swc/helpers@0.5.15))(jiti@2.4.0)(postcss@8.4.49)(typescript@5.6.3)(yaml@2.6.1)
 
+  packages/client-farcaster:
+    dependencies:
+      '@ai16z/eliza':
+        specifier: workspace:*
+        version: link:../core
+      '@farcaster/hub-nodejs':
+        specifier: ^0.12.7
+        version: 0.12.7(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8)
+      viem:
+        specifier: ^2.21.47
+        version: 2.21.50(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8)
+    devDependencies:
+      tsup:
+        specifier: ^8.3.5
+        version: 8.3.5(@swc/core@1.9.3(@swc/helpers@0.5.15))(jiti@2.4.0)(postcss@8.4.49)(typescript@5.6.3)(yaml@2.6.1)
+
   packages/client-github:
     dependencies:
       '@ai16z/eliza':
@@ -662,7 +617,7 @@ importers:
         version: 5.2.1(@types/eslint@9.6.1)(eslint-config-prettier@9.1.0(eslint@9.13.0(jiti@2.4.0)))(eslint@9.13.0(jiti@2.4.0))(prettier@3.3.3)
       eslint-plugin-vitest:
         specifier: 0.5.4
-        version: 0.5.4(@typescript-eslint/eslint-plugin@8.12.2(@typescript-eslint/parser@8.12.2(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0))
+        version: 0.5.4(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0))
       tsup:
         specifier: 8.3.5
         version: 8.3.5(@swc/core@1.9.3(@swc/helpers@0.5.15))(jiti@2.4.0)(postcss@8.4.49)(typescript@5.6.3)(yaml@2.6.1)
@@ -693,7 +648,7 @@ importers:
         version: 5.2.1(@types/eslint@9.6.1)(eslint-config-prettier@9.1.0(eslint@9.13.0(jiti@2.4.0)))(eslint@9.13.0(jiti@2.4.0))(prettier@3.3.3)
       eslint-plugin-vitest:
         specifier: 0.5.4
-        version: 0.5.4(@typescript-eslint/eslint-plugin@8.12.2(@typescript-eslint/parser@8.12.2(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0))
+        version: 0.5.4(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0))
       tsup:
         specifier: 8.3.5
         version: 8.3.5(@swc/core@1.9.3(@swc/helpers@0.5.15))(jiti@2.4.0)(postcss@8.4.49)(typescript@5.6.3)(yaml@2.6.1)
@@ -727,7 +682,7 @@ importers:
         version: 5.2.1(@types/eslint@9.6.1)(eslint-config-prettier@9.1.0(eslint@9.13.0(jiti@2.4.0)))(eslint@9.13.0(jiti@2.4.0))(prettier@3.3.3)
       eslint-plugin-vitest:
         specifier: 0.5.4
-        version: 0.5.4(@typescript-eslint/eslint-plugin@8.12.2(@typescript-eslint/parser@8.12.2(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0))
+        version: 0.5.4(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0))
       tsup:
         specifier: 8.3.5
         version: 8.3.5(@swc/core@1.9.3(@swc/helpers@0.5.15))(jiti@2.4.0)(postcss@8.4.49)(typescript@5.6.3)(yaml@2.6.1)
@@ -867,9 +822,6 @@ importers:
       eslint-plugin-prettier:
         specifier: 5.2.1
         version: 5.2.1(@types/eslint@9.6.1)(eslint-config-prettier@9.1.0(eslint@9.13.0(jiti@2.4.0)))(eslint@9.13.0(jiti@2.4.0))(prettier@3.3.3)
-      eslint-plugin-vitest:
-        specifier: 0.5.4
-        version: 0.5.4(@typescript-eslint/eslint-plugin@8.12.2(@typescript-eslint/parser@8.12.2(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0))
       jest:
         specifier: 29.7.0
         version: 29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.9.3(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3))
@@ -930,7 +882,7 @@ importers:
         version: 5.2.1(@types/eslint@9.6.1)(eslint-config-prettier@9.1.0(eslint@9.13.0(jiti@2.4.0)))(eslint@9.13.0(jiti@2.4.0))(prettier@3.3.3)
       eslint-plugin-vitest:
         specifier: 0.5.4
-        version: 0.5.4(@typescript-eslint/eslint-plugin@8.12.2(@typescript-eslint/parser@8.12.2(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0))
+        version: 0.5.4(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0))
       jiti:
         specifier: 2.4.0
         version: 2.4.0
@@ -976,7 +928,7 @@ importers:
         version: 5.2.1(@types/eslint@9.6.1)(eslint-config-prettier@9.1.0(eslint@9.13.0(jiti@2.4.0)))(eslint@9.13.0(jiti@2.4.0))(prettier@3.3.3)
       eslint-plugin-vitest:
         specifier: 0.5.4
-        version: 0.5.4(@typescript-eslint/eslint-plugin@8.12.2(@typescript-eslint/parser@8.12.2(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0))
+        version: 0.5.4(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0))
 
   packages/plugin-coinbase:
     dependencies:
@@ -1032,7 +984,7 @@ importers:
         version: 5.2.1(@types/eslint@9.6.1)(eslint-config-prettier@9.1.0(eslint@9.13.0(jiti@2.4.0)))(eslint@9.13.0(jiti@2.4.0))(prettier@3.3.3)
       eslint-plugin-vitest:
         specifier: 0.5.4
-        version: 0.5.4(@typescript-eslint/eslint-plugin@8.12.2(@typescript-eslint/parser@8.12.2(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0))
+        version: 0.5.4(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0))
 
   packages/plugin-node:
     dependencies:
@@ -1210,7 +1162,7 @@ importers:
         version: 5.2.1(@types/eslint@9.6.1)(eslint-config-prettier@9.1.0(eslint@9.13.0(jiti@2.4.0)))(eslint@9.13.0(jiti@2.4.0))(prettier@3.3.3)
       eslint-plugin-vitest:
         specifier: 0.5.4
-        version: 0.5.4(@typescript-eslint/eslint-plugin@8.12.2(@typescript-eslint/parser@8.12.2(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0))
+        version: 0.5.4(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0))
       tsup:
         specifier: 8.3.5
         version: 8.3.5(@swc/core@1.9.3(@swc/helpers@0.5.15))(jiti@2.4.0)(postcss@8.4.49)(typescript@5.6.3)(yaml@2.6.1)
@@ -1250,6 +1202,9 @@ importers:
       tsup:
         specifier: 8.3.5
         version: 8.3.5(@swc/core@1.9.3(@swc/helpers@0.5.15))(jiti@2.4.0)(postcss@8.4.49)(typescript@5.6.3)(yaml@2.6.1)
+      vitest:
+        specifier: 2.1.4
+        version: 2.1.4(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0)
       whatwg-url:
         specifier: 7.1.0
         version: 7.1.0
@@ -1265,7 +1220,7 @@ importers:
         version: 5.2.1(@types/eslint@9.6.1)(eslint-config-prettier@9.1.0(eslint@9.13.0(jiti@2.4.0)))(eslint@9.13.0(jiti@2.4.0))(prettier@3.3.3)
       eslint-plugin-vitest:
         specifier: 0.5.4
-        version: 0.5.4(@typescript-eslint/eslint-plugin@8.12.2(@typescript-eslint/parser@8.12.2(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0))
+        version: 0.5.4(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.4(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0))
 
   packages/plugin-starknet:
     dependencies:
@@ -1308,7 +1263,7 @@ importers:
         version: 5.2.1(@types/eslint@9.6.1)(eslint-config-prettier@9.1.0(eslint@9.13.0(jiti@2.4.0)))(eslint@9.13.0(jiti@2.4.0))(prettier@3.3.3)
       eslint-plugin-vitest:
         specifier: 0.5.4
-        version: 0.5.4(@typescript-eslint/eslint-plugin@8.12.2(@typescript-eslint/parser@8.12.2(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0))
+        version: 0.5.4(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0))
 
   packages/plugin-trustdb:
     dependencies:
@@ -1345,7 +1300,7 @@ importers:
         version: 5.2.1(@types/eslint@9.6.1)(eslint-config-prettier@9.1.0(eslint@9.13.0(jiti@2.4.0)))(eslint@9.13.0(jiti@2.4.0))(prettier@3.3.3)
       eslint-plugin-vitest:
         specifier: 0.5.4
-        version: 0.5.4(@typescript-eslint/eslint-plugin@8.12.2(@typescript-eslint/parser@8.12.2(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0))
+        version: 0.5.4(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0))
 
   packages/plugin-video-generation:
     dependencies:
@@ -1370,7 +1325,7 @@ importers:
         version: 5.2.1(@types/eslint@9.6.1)(eslint-config-prettier@9.1.0(eslint@9.13.0(jiti@2.4.0)))(eslint@9.13.0(jiti@2.4.0))(prettier@3.3.3)
       eslint-plugin-vitest:
         specifier: 0.5.4
-        version: 0.5.4(@typescript-eslint/eslint-plugin@8.12.2(@typescript-eslint/parser@8.12.2(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0))
+        version: 0.5.4(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0))
 
 packages:
 
@@ -1379,6 +1334,10 @@ packages:
     peerDependencies:
       ethers: 6.13.1
 
+  '@acuminous/bitsyntax@0.1.2':
+    resolution: {integrity: sha512-29lUK80d1muEQqiUsSo+3A0yP6CdspgC95EnKBMi22Xlwt79i/En4Vr67+cXhU+cZjbti3TgGGC5wy1stIywVQ==}
+    engines: {node: '>=0.8'}
+
   '@adraffy/ens-normalize@1.10.1':
     resolution: {integrity: sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==}
 
@@ -3692,6 +3651,16 @@ packages:
   '@ethersproject/strings@5.7.0':
     resolution: {integrity: sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==}
 
+  '@faker-js/faker@7.6.0':
+    resolution: {integrity: sha512-XK6BTq1NDMo9Xqw/YkYyGjSsg44fbNwYRx7QK2CuoQgyy+f1rrTDHoExVM5PsyXCtfl2vs2vVJ0MN0yN6LppRw==}
+    engines: {node: '>=14.0.0', npm: '>=6.0.0'}
+
+  '@farcaster/core@0.15.6':
+    resolution: {integrity: sha512-Vxq2JhqdZYEMjH4PIwPXQkalY46S4Mol2oCSHUafXenDx6WSoQJqF/4an4KyxGQbmA7Cf8+hl6zuNzkkHXEUyQ==}
+
+  '@farcaster/hub-nodejs@0.12.7':
+    resolution: {integrity: sha512-05zXNqnHRBSbOkHl0KDh6l60nHK5MiKFky0JBGbdOZXdkFCk4FIiHv9AGLxjFXr/FxA3jSTHUJfvRRe5TonjRw==}
+
   '@floating-ui/core@1.6.8':
     resolution: {integrity: sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==}
 
@@ -3711,6 +3680,15 @@ packages:
     resolution: {integrity: sha512-8brlcJwFXI4fPuBtsDNQqCdWZmz8gV9jeEKOU0vc5H2SjehCQpXK/NwuSEr916zbhlBHtg/sU37qQQdgvh5BRA==}
     engines: {node: '>=18.0.0'}
 
+  '@grpc/grpc-js@1.11.3':
+    resolution: {integrity: sha512-i9UraDzFHMR+Iz/MhFLljT+fCpgxZ3O6CxwGJ8YuNYHJItIHUzKJpW2LvoFZNnGPwqc9iWy9RAucxV0JoR9aUQ==}
+    engines: {node: '>=12.10.0'}
+
+  '@grpc/proto-loader@0.7.13':
+    resolution: {integrity: sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw==}
+    engines: {node: '>=6'}
+    hasBin: true
+
   '@hapi/hoek@9.3.0':
     resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==}
 
@@ -3972,6 +3950,9 @@ packages:
   '@jridgewell/trace-mapping@0.3.9':
     resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
 
+  '@js-sdsl/ordered-map@4.4.2':
+    resolution: {integrity: sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==}
+
   '@kikobeats/time-span@1.0.5':
     resolution: {integrity: sha512-txRAdmi35N1wnsLS1AO5mTlbY5Cv5/61WXqek2y3L9Q7u4mgdUVq819so5xe753hL5gYeLzlWoJ/VJfXg9nx8g==}
     engines: {node: '>= 18'}
@@ -6353,9 +6334,23 @@ packages:
     peerDependencies:
       vite: ^4.2.0 || ^5.0.0
 
+  '@vitest/expect@2.1.4':
+    resolution: {integrity: sha512-DOETT0Oh1avie/D/o2sgMHGrzYUFFo3zqESB2Hn70z6QB1HrS2IQ9z5DfyTqU8sg4Bpu13zZe9V4+UTNQlUeQA==}
+
   '@vitest/expect@2.1.5':
     resolution: {integrity: sha512-nZSBTW1XIdpZvEJyoP/Sy8fUg0b8od7ZpGDkTUcfJ7wz/VoZAFzFfLyxVxGFhUjJzhYqSbIpfMtl/+k/dpWa3Q==}
 
+  '@vitest/mocker@2.1.4':
+    resolution: {integrity: sha512-Ky/O1Lc0QBbutJdW0rqLeFNbuLEyS+mIPiNdlVlp2/yhJ0SbyYqObS5IHdhferJud8MbbwMnexg4jordE5cCoQ==}
+    peerDependencies:
+      msw: ^2.4.9
+      vite: ^5.0.0
+    peerDependenciesMeta:
+      msw:
+        optional: true
+      vite:
+        optional: true
+
   '@vitest/mocker@2.1.5':
     resolution: {integrity: sha512-XYW6l3UuBmitWqSUXTNXcVBUCRytDogBsWuNXQijc00dtnU/9OqpXWp4OJroVrad/gLIomAq9aW8yWDBtMthhQ==}
     peerDependencies:
@@ -6367,18 +6362,33 @@ packages:
       vite:
         optional: true
 
+  '@vitest/pretty-format@2.1.4':
+    resolution: {integrity: sha512-L95zIAkEuTDbUX1IsjRl+vyBSLh3PwLLgKpghl37aCK9Jvw0iP+wKwIFhfjdUtA2myLgjrG6VU6JCFLv8q/3Ww==}
+
   '@vitest/pretty-format@2.1.5':
     resolution: {integrity: sha512-4ZOwtk2bqG5Y6xRGHcveZVr+6txkH7M2e+nPFd6guSoN638v/1XQ0K06eOpi0ptVU/2tW/pIU4IoPotY/GZ9fw==}
 
+  '@vitest/runner@2.1.4':
+    resolution: {integrity: sha512-sKRautINI9XICAMl2bjxQM8VfCMTB0EbsBc/EDFA57V6UQevEKY/TOPOF5nzcvCALltiLfXWbq4MaAwWx/YxIA==}
+
   '@vitest/runner@2.1.5':
     resolution: {integrity: sha512-pKHKy3uaUdh7X6p1pxOkgkVAFW7r2I818vHDthYLvUyjRfkKOU6P45PztOch4DZarWQne+VOaIMwA/erSSpB9g==}
 
+  '@vitest/snapshot@2.1.4':
+    resolution: {integrity: sha512-3Kab14fn/5QZRog5BPj6Rs8dc4B+mim27XaKWFWHWA87R56AKjHTGcBFKpvZKDzC4u5Wd0w/qKsUIio3KzWW4Q==}
+
   '@vitest/snapshot@2.1.5':
     resolution: {integrity: sha512-zmYw47mhfdfnYbuhkQvkkzYroXUumrwWDGlMjpdUr4jBd3HZiV2w7CQHj+z7AAS4VOtWxI4Zt4bWt4/sKcoIjg==}
 
+  '@vitest/spy@2.1.4':
+    resolution: {integrity: sha512-4JOxa+UAizJgpZfaCPKK2smq9d8mmjZVPMt2kOsg/R8QkoRzydHH1qHxIYNvr1zlEaFj4SXiaaJWxq/LPLKaLg==}
+
   '@vitest/spy@2.1.5':
     resolution: {integrity: sha512-aWZF3P0r3w6DiYTVskOYuhBc7EMc3jvn1TkBg8ttylFFRqNN2XGD7V5a4aQdk6QiUzZQ4klNBSpCLJgWNdIiNw==}
 
+  '@vitest/utils@2.1.4':
+    resolution: {integrity: sha512-MXDnZn0Awl2S86PSNIim5PWXgIAx8CIkzu35mBdSApUip6RFOGXBCf3YFyeEu8n1IHk4bWD46DeYFu9mQlFIRg==}
+
   '@vitest/utils@2.1.5':
     resolution: {integrity: sha512-yfj6Yrp0Vesw2cwJbP+cl04OC+IHFsuQsrsJBL9pyGeQXE56v1UAOQco+SR55Vf1nQzfV0QJg1Qum7AaWUwwYg==}
 
@@ -6920,6 +6930,9 @@ packages:
   base-x@3.0.10:
     resolution: {integrity: sha512-7d0s06rR9rYaIWHkpfLIFICM/tkSVdoPC9qYAQRpxn9DdKNWNsKC0uk++akckyLq16Tx2WIinnZ6WRriAt6njQ==}
 
+  base-x@4.0.0:
+    resolution: {integrity: sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw==}
+
   base-x@5.0.0:
     resolution: {integrity: sha512-sMW3VGSX1QWVFA6l8U62MLKz29rRfpTlYdCqLdpLo1/Yd4zZwSbnUaDfciIAowAqvq7YFnWq9hrhdg1KYgc1lQ==}
 
@@ -7065,6 +7078,9 @@ packages:
   bs58@4.0.1:
     resolution: {integrity: sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==}
 
+  bs58@5.0.0:
+    resolution: {integrity: sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==}
+
   bs58@6.0.0:
     resolution: {integrity: sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==}
 
@@ -11405,6 +11421,9 @@ packages:
     resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==}
     engines: {node: '>= 0.4.0'}
 
+  neverthrow@6.2.2:
+    resolution: {integrity: sha512-POR1FACqdK9jH0S2kRPzaZEvzT11wsOxLW520PQV/+vKi9dQe+hXq19EiOvYx7lSRaF5VB9lYGsPInynrnN05w==}
+
   next-tick@1.1.0:
     resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==}
 
@@ -14985,6 +15004,11 @@ packages:
       typescript:
         optional: true
 
+  vite-node@2.1.4:
+    resolution: {integrity: sha512-kqa9v+oi4HwkG6g8ufRnb5AeplcRw8jUF6/7/Qz1qRQOXHImG8YnLbB+LLszENwFnoBl9xIf9nVdCFzNd7GQEg==}
+    engines: {node: ^18.0.0 || >=20.0.0}
+    hasBin: true
+
   vite-node@2.1.5:
     resolution: {integrity: sha512-rd0QIgx74q4S1Rd56XIiL2cYEdyWn13cunYBIuqh9mpmQr7gGS0IxXoP8R6OaZtNQQLyXSWbd4rXKYUbhFpK5w==}
     engines: {node: ^18.0.0 || >=20.0.0}
@@ -15031,6 +15055,31 @@ packages:
       terser:
         optional: true
 
+  vitest@2.1.4:
+    resolution: {integrity: sha512-eDjxbVAJw1UJJCHr5xr/xM86Zx+YxIEXGAR+bmnEID7z9qWfoxpHw0zdobz+TQAFOLT+nEXz3+gx6nUJ7RgmlQ==}
+    engines: {node: ^18.0.0 || >=20.0.0}
+    hasBin: true
+    peerDependencies:
+      '@edge-runtime/vm': '*'
+      '@types/node': ^18.0.0 || >=20.0.0
+      '@vitest/browser': 2.1.4
+      '@vitest/ui': 2.1.4
+      happy-dom: '*'
+      jsdom: '*'
+    peerDependenciesMeta:
+      '@edge-runtime/vm':
+        optional: true
+      '@types/node':
+        optional: true
+      '@vitest/browser':
+        optional: true
+      '@vitest/ui':
+        optional: true
+      happy-dom:
+        optional: true
+      jsdom:
+        optional: true
+
   vitest@2.1.5:
     resolution: {integrity: sha512-P4ljsdpuzRTPI/kbND2sDZ4VmieerR2c9szEZpjc+98Z9ebvnXmM5+0tHEKqYZumXqlvnmfWsjeFOjXVriDG7A==}
     engines: {node: ^18.0.0 || >=20.0.0}
@@ -15495,6 +15544,14 @@ snapshots:
       - supports-color
       - utf-8-validate
 
+  '@acuminous/bitsyntax@0.1.2':
+    dependencies:
+      buffer-more-ints: 1.0.0
+      debug: 4.3.7(supports-color@5.5.0)
+      safe-buffer: 5.1.2
+    transitivePeerDependencies:
+      - supports-color
+
   '@adraffy/ens-normalize@1.10.1': {}
 
   '@adraffy/ens-normalize@1.11.0': {}
@@ -18999,6 +19056,34 @@ snapshots:
       '@ethersproject/constants': 5.7.0
       '@ethersproject/logger': 5.7.0
 
+  '@faker-js/faker@7.6.0': {}
+
+  '@farcaster/core@0.15.6(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8)':
+    dependencies:
+      '@faker-js/faker': 7.6.0
+      '@noble/curves': 1.7.0
+      '@noble/hashes': 1.6.1
+      bs58: 5.0.0
+      neverthrow: 6.2.2
+      viem: 2.21.50(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8)
+    transitivePeerDependencies:
+      - bufferutil
+      - typescript
+      - utf-8-validate
+      - zod
+
+  '@farcaster/hub-nodejs@0.12.7(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8)':
+    dependencies:
+      '@farcaster/core': 0.15.6(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8)
+      '@grpc/grpc-js': 1.11.3
+      '@noble/hashes': 1.6.1
+      neverthrow: 6.2.2
+    transitivePeerDependencies:
+      - bufferutil
+      - typescript
+      - utf-8-validate
+      - zod
+
   '@floating-ui/core@1.6.8':
     dependencies:
       '@floating-ui/utils': 0.2.8
@@ -19023,6 +19108,18 @@ snapshots:
       - encoding
       - supports-color
 
+  '@grpc/grpc-js@1.11.3':
+    dependencies:
+      '@grpc/proto-loader': 0.7.13
+      '@js-sdsl/ordered-map': 4.4.2
+
+  '@grpc/proto-loader@0.7.13':
+    dependencies:
+      lodash.camelcase: 4.3.0
+      long: 5.2.3
+      protobufjs: 7.4.0
+      yargs: 17.7.2
+
   '@hapi/hoek@9.3.0': {}
 
   '@hapi/topo@5.1.0':
@@ -19358,6 +19455,8 @@ snapshots:
       '@jridgewell/resolve-uri': 3.1.2
       '@jridgewell/sourcemap-codec': 1.5.0
 
+  '@js-sdsl/ordered-map@4.4.2': {}
+
   '@kikobeats/time-span@1.0.5': {}
 
   '@kwsites/file-exists@1.1.1':
@@ -22296,6 +22395,13 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
+  '@vitest/expect@2.1.4':
+    dependencies:
+      '@vitest/spy': 2.1.4
+      '@vitest/utils': 2.1.4
+      chai: 5.1.2
+      tinyrainbow: 1.2.0
+
   '@vitest/expect@2.1.5':
     dependencies:
       '@vitest/spy': 2.1.5
@@ -22303,6 +22409,14 @@ snapshots:
       chai: 5.1.2
       tinyrainbow: 1.2.0
 
+  '@vitest/mocker@2.1.4(vite@5.4.11(@types/node@22.8.4)(terser@5.36.0))':
+    dependencies:
+      '@vitest/spy': 2.1.4
+      estree-walker: 3.0.3
+      magic-string: 0.30.13
+    optionalDependencies:
+      vite: 5.4.11(@types/node@22.8.4)(terser@5.36.0)
+
   '@vitest/mocker@2.1.5(vite@5.4.11(@types/node@22.8.4)(terser@5.36.0))':
     dependencies:
       '@vitest/spy': 2.1.5
@@ -22311,25 +22425,50 @@ snapshots:
     optionalDependencies:
       vite: 5.4.11(@types/node@22.8.4)(terser@5.36.0)
 
+  '@vitest/pretty-format@2.1.4':
+    dependencies:
+      tinyrainbow: 1.2.0
+
   '@vitest/pretty-format@2.1.5':
     dependencies:
       tinyrainbow: 1.2.0
 
+  '@vitest/runner@2.1.4':
+    dependencies:
+      '@vitest/utils': 2.1.4
+      pathe: 1.1.2
+
   '@vitest/runner@2.1.5':
     dependencies:
       '@vitest/utils': 2.1.5
       pathe: 1.1.2
 
+  '@vitest/snapshot@2.1.4':
+    dependencies:
+      '@vitest/pretty-format': 2.1.4
+      magic-string: 0.30.13
+      pathe: 1.1.2
+
   '@vitest/snapshot@2.1.5':
     dependencies:
       '@vitest/pretty-format': 2.1.5
       magic-string: 0.30.13
       pathe: 1.1.2
 
+  '@vitest/spy@2.1.4':
+    dependencies:
+      tinyspy: 3.0.2
+
   '@vitest/spy@2.1.5':
     dependencies:
       tinyspy: 3.0.2
 
+  '@vitest/utils@2.1.4':
+    dependencies:
+      '@vitest/pretty-format': 2.1.4
+      loupe: 3.1.2
+      tinyrainbow: 1.2.0
+
   '@vitest/utils@2.1.5':
     dependencies:
       '@vitest/pretty-format': 2.1.5
@@ -23030,6 +23169,8 @@ snapshots:
     dependencies:
       safe-buffer: 5.2.1
 
+  base-x@4.0.0: {}
+
   base-x@5.0.0: {}
 
   base64-js@1.5.1: {}
@@ -23206,6 +23347,10 @@ snapshots:
     dependencies:
       base-x: 3.0.10
 
+  bs58@5.0.0:
+    dependencies:
+      base-x: 4.0.0
+
   bs58@6.0.0:
     dependencies:
       base-x: 5.0.0
@@ -25019,12 +25164,21 @@ snapshots:
     dependencies:
       eslint: 9.13.0(jiti@2.4.0)
 
-  eslint-plugin-vitest@0.5.4(@typescript-eslint/eslint-plugin@8.12.2(@typescript-eslint/parser@8.12.2(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0)):
+  eslint-plugin-vitest@0.5.4(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.4(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0)):
+    dependencies:
+      '@typescript-eslint/utils': 7.18.0(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)
+      eslint: 9.13.0(jiti@2.4.0)
+    optionalDependencies:
+      vitest: 2.1.4(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0)
+    transitivePeerDependencies:
+      - supports-color
+      - typescript
+
+  eslint-plugin-vitest@0.5.4(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0)):
     dependencies:
       '@typescript-eslint/utils': 7.18.0(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)
       eslint: 9.13.0(jiti@2.4.0)
     optionalDependencies:
-      '@typescript-eslint/eslint-plugin': 8.12.2(@typescript-eslint/parser@8.12.2(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.0))(typescript@5.6.3)
       vitest: 2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0)
     transitivePeerDependencies:
       - supports-color
@@ -25316,7 +25470,7 @@ snapshots:
 
   extract-zip@2.0.1:
     dependencies:
-      debug: 4.3.4
+      debug: 4.3.7(supports-color@5.5.0)
       get-stream: 5.2.0
       yauzl: 2.10.0
     optionalDependencies:
@@ -28657,6 +28811,8 @@ snapshots:
 
   netmask@2.0.2: {}
 
+  neverthrow@6.2.2: {}
+
   next-tick@1.1.0: {}
 
   no-case@3.0.4:
@@ -32332,7 +32488,6 @@ snapshots:
       '@jest/transform': 29.7.0
       '@jest/types': 29.6.3
       babel-jest: 29.7.0(@babel/core@7.26.0)
-      esbuild: 0.24.0
 
   ts-mixer@6.0.4: {}
 
@@ -32820,6 +32975,23 @@ snapshots:
       - utf-8-validate
       - zod
 
+  vite-node@2.1.4(@types/node@22.8.4)(terser@5.36.0):
+    dependencies:
+      cac: 6.7.14
+      debug: 4.3.7(supports-color@5.5.0)
+      pathe: 1.1.2
+      vite: 5.4.11(@types/node@22.8.4)(terser@5.36.0)
+    transitivePeerDependencies:
+      - '@types/node'
+      - less
+      - lightningcss
+      - sass
+      - sass-embedded
+      - stylus
+      - sugarss
+      - supports-color
+      - terser
+
   vite-node@2.1.5(@types/node@22.8.4)(terser@5.36.0):
     dependencies:
       cac: 6.7.14
@@ -32862,6 +33034,42 @@ snapshots:
       fsevents: 2.3.3
       terser: 5.36.0
 
+  vitest@2.1.4(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0):
+    dependencies:
+      '@vitest/expect': 2.1.4
+      '@vitest/mocker': 2.1.4(vite@5.4.11(@types/node@22.8.4)(terser@5.36.0))
+      '@vitest/pretty-format': 2.1.5
+      '@vitest/runner': 2.1.4
+      '@vitest/snapshot': 2.1.4
+      '@vitest/spy': 2.1.4
+      '@vitest/utils': 2.1.4
+      chai: 5.1.2
+      debug: 4.3.7(supports-color@5.5.0)
+      expect-type: 1.1.0
+      magic-string: 0.30.13
+      pathe: 1.1.2
+      std-env: 3.8.0
+      tinybench: 2.9.0
+      tinyexec: 0.3.1
+      tinypool: 1.0.2
+      tinyrainbow: 1.2.0
+      vite: 5.4.11(@types/node@22.8.4)(terser@5.36.0)
+      vite-node: 2.1.4(@types/node@22.8.4)(terser@5.36.0)
+      why-is-node-running: 2.3.0
+    optionalDependencies:
+      '@types/node': 22.8.4
+      jsdom: 25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10)
+    transitivePeerDependencies:
+      - less
+      - lightningcss
+      - msw
+      - sass
+      - sass-embedded
+      - stylus
+      - sugarss
+      - supports-color
+      - terser
+
   vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.36.0):
     dependencies:
       '@vitest/expect': 2.1.5

From 5e7274c879f1aa57f65ce8d210528ef4b7eb6087 Mon Sep 17 00:00:00 2001
From: MarcoMandar <malicemandar@gmail.com>
Date: Tue, 26 Nov 2024 00:06:56 +0200
Subject: [PATCH 11/12] tokenRecommendation uuid

Signed-off-by: MarcoMandar <malicemandar@gmail.com>
---
 packages/plugin-solana/src/providers/trustScoreProvider.ts | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/packages/plugin-solana/src/providers/trustScoreProvider.ts b/packages/plugin-solana/src/providers/trustScoreProvider.ts
index 394fb32387e..d09e1126248 100644
--- a/packages/plugin-solana/src/providers/trustScoreProvider.ts
+++ b/packages/plugin-solana/src/providers/trustScoreProvider.ts
@@ -19,6 +19,7 @@ import {
 } from "@ai16z/plugin-trustdb";
 import { settings } from "@ai16z/eliza";
 import { IAgentRuntime, Memory, Provider, State } from "@ai16z/eliza";
+import { v4 as uuidv4 } from "uuid";
 
 const Wallet = settings.MAIN_WALLET_ADDRESS;
 interface TradeData {
@@ -391,8 +392,10 @@ export class TrustScoreManager {
             rapidDump: false,
         };
         this.trustScoreDb.addTradePerformance(creationData, data.is_simulation);
-
+        // generate unique uuid for each TokenRecommendation
+        const tokenUUId = uuidv4();
         const tokenRecommendation: TokenRecommendation = {
+            id: tokenUUId,
             recommenderId: recommenderId,
             tokenAddress: tokenAddress,
             timestamp: new Date(),

From 4d832408d76a03ff12be819c6a11395ea50c76b7 Mon Sep 17 00:00:00 2001
From: MarcoMandar <malicemandar@gmail.com>
Date: Tue, 26 Nov 2024 00:40:08 +0200
Subject: [PATCH 12/12] update api call

Signed-off-by: MarcoMandar <malicemandar@gmail.com>
---
 .../plugin-solana/src/providers/simulationSellingService.ts    | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/packages/plugin-solana/src/providers/simulationSellingService.ts b/packages/plugin-solana/src/providers/simulationSellingService.ts
index 20c92fb60f3..88b8729f5cd 100644
--- a/packages/plugin-solana/src/providers/simulationSellingService.ts
+++ b/packages/plugin-solana/src/providers/simulationSellingService.ts
@@ -211,6 +211,7 @@ export class simulationSellingService {
                 const process = await this.startProcessInTheSonarBackend(
                     tokenAddress,
                     balance,
+                    true,
                     sell_recommender_id,
                     tokenPerformance.initial_mc
                 );
@@ -225,6 +226,7 @@ export class simulationSellingService {
         tokenAddress: string,
         balance: number,
         isSimulation: boolean,
+        sell_recommender_id: string,
         initial_mc: number
     ) {
         try {
@@ -233,6 +235,7 @@ export class simulationSellingService {
                 balance,
                 isSimulation,
                 initial_mc,
+                sell_recommender_id,
             });
             const response = await fetch(
                 `${this.sonarBe}/ai16z-sol/startProcess`,