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 1/6] 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 2/6] 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 3/6] 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 4/6] 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 5/6] 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 6/6] 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),
         }));
     }