From 362470ad51a96ec2599a4a5496ce2e4754809133 Mon Sep 17 00:00:00 2001
From: MarcoMandar <malicemandar@gmail.com>
Date: Sat, 2 Nov 2024 14:55:10 +0200
Subject: [PATCH 1/2] update virtualConfidence

Signed-off-by: MarcoMandar <malicemandar@gmail.com>
---
 core/src/providers/trustScoreProvider.ts | 30 +++++++++++++++++++++---
 1 file changed, 27 insertions(+), 3 deletions(-)

diff --git a/core/src/providers/trustScoreProvider.ts b/core/src/providers/trustScoreProvider.ts
index 0077d926f43..f1a4df47df2 100644
--- a/core/src/providers/trustScoreProvider.ts
+++ b/core/src/providers/trustScoreProvider.ts
@@ -7,7 +7,7 @@ import {
     // HolderData,
 } from "../types/token";
 import { Connection, PublicKey } from "@solana/web3.js";
-
+import { getAssociatedTokenAddress } from "@solana/spl-token";
 import { TokenProvider } from "./token";
 import WalletProvider from "./balances";
 import {
@@ -30,6 +30,8 @@ interface sellDetails {
 export class TrustScoreProvider {
     private tokenProvider: TokenProvider;
     private trustScoreDb: TrustScoreDatabase;
+    private connection: Connection = new Connection(process.env.RPC_URL!);
+    private baseMint: PublicKey = new PublicKey(process.env.BASE_MINT!);
 
     constructor(
         tokenProvider: TokenProvider,
@@ -38,6 +40,25 @@ export class TrustScoreProvider {
         this.tokenProvider = tokenProvider;
         this.trustScoreDb = trustScoreDb;
     }
+
+    //getRecommenederBalance
+    async getRecommenederBalance(recommenderWallet: string): Promise<number> {
+        try {
+            const tokenAta = await getAssociatedTokenAddress(
+                new PublicKey(recommenderWallet),
+                this.baseMint
+            );
+            const tokenBalInfo =
+                await this.connection.getTokenAccountBalance(tokenAta);
+            const tokenBalance = tokenBalInfo.value.amount;
+            const balance = parseFloat(tokenBalance);
+            return balance;
+        } catch (error) {
+            console.error("Error fetching balance", error);
+            return 0;
+        }
+    }
+
     /**
      * Generates and saves trust score based on processed token data and user recommendations.
      * @param tokenAddress The address of the token to analyze.
@@ -46,7 +67,8 @@ export class TrustScoreProvider {
      */
     async generateTrustScore(
         tokenAddress: string,
-        recommenderId: string
+        recommenderId: string,
+        recommenderWallet: string
     ): Promise<{
         tokenPerformance: TokenPerformance;
         recommenderMetrics: RecommenderMetrics;
@@ -61,6 +83,8 @@ export class TrustScoreProvider {
         const isRapidDump = await this.isRapidDump(tokenAddress);
         const sustainedGrowth = await this.sustainedGrowth(tokenAddress);
         const suspiciousVolume = await this.suspiciousVolume(tokenAddress);
+        const balance = await this.getRecommenederBalance(recommenderWallet);
+        const virtualConfidence = balance / 1000000; // TODO: create formula to calculate virtual confidence based on user balance
 
         return {
             tokenPerformance: {
@@ -93,7 +117,7 @@ export class TrustScoreProvider {
                 avgTokenPerformance: recommenderMetrics.avgTokenPerformance,
                 riskScore: recommenderMetrics.riskScore,
                 consistencyScore: recommenderMetrics.consistencyScore,
-                virtualConfidence: recommenderMetrics.virtualConfidence,
+                virtualConfidence: virtualConfidence,
                 lastUpdated: new Date(),
             },
         };

From c988337e69ef26a2ff7be198dfeaabd5475bac33 Mon Sep 17 00:00:00 2001
From: MarcoMandar <malicemandar@gmail.com>
Date: Sun, 3 Nov 2024 04:02:30 +0200
Subject: [PATCH 2/2] add last active and decay score, update token
 recommendations, add validation trust to token performance and add
 calculateValidationTrust

Signed-off-by: MarcoMandar <malicemandar@gmail.com>
---
 core/src/adapters/trustScoreDatabase.ts  | 48 +++++++++++++++++++++++-
 core/src/providers/trustScoreProvider.ts | 39 +++++++++++++++++--
 2 files changed, 83 insertions(+), 4 deletions(-)

diff --git a/core/src/adapters/trustScoreDatabase.ts b/core/src/adapters/trustScoreDatabase.ts
index 9ec19de29ac..b206fd1923e 100644
--- a/core/src/adapters/trustScoreDatabase.ts
+++ b/core/src/adapters/trustScoreDatabase.ts
@@ -24,6 +24,8 @@ export interface RecommenderMetrics {
     riskScore: number;
     consistencyScore: number;
     virtualConfidence: number;
+    lastActiveDate: Date;
+    trustDecay: number;
     lastUpdated: Date;
 }
 
@@ -41,6 +43,7 @@ export interface TokenPerformance {
     sustainedGrowth: boolean;
     rapidDump: boolean;
     suspiciousVolume: boolean;
+    validationTrust: number;
     lastUpdated: Date;
 }
 
@@ -63,6 +66,7 @@ export interface RecommenderMetricsHistory {
     riskScore: number;
     consistencyScore: number;
     virtualConfidence: number;
+    trustDecay: number;
     recordedAt: Date;
 }
 
@@ -100,6 +104,8 @@ interface RecommenderMetricsRow {
     risk_score: number;
     consistency_score: number;
     virtual_confidence: number;
+    last_active_date: Date;
+    trust_decay: number;
     last_updated: string;
 }
 
@@ -117,6 +123,7 @@ interface TokenPerformanceRow {
     sustained_growth: number;
     rapid_dump: number;
     suspicious_volume: number;
+    validation_trust: number;
     last_updated: string;
 }
 
@@ -165,6 +172,8 @@ export class TrustScoreDatabase {
                 risk_score REAL DEFAULT 0,
                 consistency_score REAL DEFAULT 0,
                 virtual_confidence REAL DEFAULT 0,
+                last_active_date DATETIME DEFAULT CURRENT_TIMESTAMP
+                trust_decay REAL DEFAULT 0,
                 last_updated DATETIME DEFAULT CURRENT_TIMESTAMP,
                 FOREIGN KEY (recommender_id) REFERENCES recommenders(id) ON DELETE CASCADE
             );
@@ -186,6 +195,7 @@ export class TrustScoreDatabase {
                 sustained_growth BOOLEAN DEFAULT FALSE,
                 rapid_dump BOOLEAN DEFAULT FALSE,
                 suspicious_volume BOOLEAN DEFAULT FALSE,
+                validation_trust REAL DEFAULT 0,
                 last_updated DATETIME DEFAULT CURRENT_TIMESTAMP
             );
         `);
@@ -378,6 +388,8 @@ export class TrustScoreDatabase {
             riskScore: row.risk_score,
             consistencyScore: row.consistency_score,
             virtualConfidence: row.virtual_confidence,
+            lastActiveDate: row.last_active_date,
+            trustDecay: row.trust_decay,
             lastUpdated: new Date(row.last_updated),
         };
     }
@@ -407,6 +419,7 @@ export class TrustScoreDatabase {
             riskScore: currentMetrics.riskScore,
             consistencyScore: currentMetrics.consistencyScore,
             virtualConfidence: currentMetrics.virtualConfidence,
+            trustDecay: currentMetrics.trustDecay,
             recordedAt: new Date(), // Current timestamp
         };
 
@@ -492,6 +505,10 @@ export class TrustScoreDatabase {
      * @param performance TokenPerformance object
      */
     upsertTokenPerformance(performance: TokenPerformance): boolean {
+        const validationTrust = this.calculateValidationTrust(
+            performance.tokenAddress
+        );
+
         const sql = `
             INSERT INTO token_performance (
                 token_address,
@@ -507,6 +524,7 @@ export class TrustScoreDatabase {
                 sustained_growth,
                 rapid_dump,
                 suspicious_volume,
+                validation_trust,
                 last_updated
             ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
             ON CONFLICT(token_address) DO UPDATE SET
@@ -522,6 +540,7 @@ export class TrustScoreDatabase {
                 sustained_growth = excluded.sustained_growth,
                 rapid_dump = excluded.rapid_dump,
                 suspicious_volume = excluded.suspicious_volume,
+                validation_trust = excluded.validation_trust,
                 last_updated = CURRENT_TIMESTAMP;
         `;
         try {
@@ -536,7 +555,8 @@ export class TrustScoreDatabase {
                 performance.marketCapChange24h,
                 performance.sustainedGrowth ? 1 : 0,
                 performance.rapidDump ? 1 : 0,
-                performance.suspiciousVolume ? 1 : 0
+                performance.suspiciousVolume ? 1 : 0,
+                validationTrust
             );
             console.log(
                 `Upserted token performance for ${performance.tokenAddress}`
@@ -574,12 +594,36 @@ export class TrustScoreDatabase {
             sustainedGrowth: row.sustained_growth === 1,
             rapidDump: row.rapid_dump === 1,
             suspiciousVolume: row.suspicious_volume === 1,
+            validationTrust: row.validation_trust,
             lastUpdated: new Date(row.last_updated),
         };
     }
 
     // ----- TokenRecommendations Methods -----
 
+    /**
+     * Calculates the average trust score of all recommenders who have recommended a specific token.
+     * @param tokenAddress The address of the token.
+     * @returns The average trust score (validationTrust).
+     */
+    calculateValidationTrust(tokenAddress: string): number {
+        const sql = `
+        SELECT rm.trust_score
+        FROM token_recommendations tr
+        JOIN recommender_metrics rm ON tr.recommender_id = rm.recommender_id
+        WHERE tr.token_address = ?;
+    `;
+        const rows = this.db.prepare(sql).all(tokenAddress) as Array<{
+            trust_score: number;
+        }>;
+
+        if (rows.length === 0) return 0; // No recommendations found
+
+        const totalTrust = rows.reduce((acc, row) => acc + row.trust_score, 0);
+        const averageTrust = totalTrust / rows.length;
+        return averageTrust;
+    }
+
     /**
      * Adds a new token recommendation.
      * @param recommendation TokenRecommendation object
@@ -735,6 +779,7 @@ export class TrustScoreDatabase {
             risk_score: number;
             consistency_score: number;
             virtual_confidence: number;
+            trust_decay: number;
             recorded_at: string;
         }>;
 
@@ -748,6 +793,7 @@ export class TrustScoreDatabase {
             riskScore: row.risk_score,
             consistencyScore: row.consistency_score,
             virtualConfidence: row.virtual_confidence,
+            trustDecay: row.trust_decay,
             recordedAt: new Date(row.recorded_at),
         }));
     }
diff --git a/core/src/providers/trustScoreProvider.ts b/core/src/providers/trustScoreProvider.ts
index f1a4df47df2..1932d9ba587 100644
--- a/core/src/providers/trustScoreProvider.ts
+++ b/core/src/providers/trustScoreProvider.ts
@@ -32,7 +32,8 @@ export class TrustScoreProvider {
     private trustScoreDb: TrustScoreDatabase;
     private connection: Connection = new Connection(process.env.RPC_URL!);
     private baseMint: PublicKey = new PublicKey(process.env.BASE_MINT!);
-
+    private DECAY_RATE = 0.95;
+    private MAX_DECAY_DAYS = 30;
     constructor(
         tokenProvider: TokenProvider,
         trustScoreDb: TrustScoreDatabase
@@ -85,6 +86,18 @@ export class TrustScoreProvider {
         const suspiciousVolume = await this.suspiciousVolume(tokenAddress);
         const balance = await this.getRecommenederBalance(recommenderWallet);
         const virtualConfidence = balance / 1000000; // TODO: create formula to calculate virtual confidence based on user balance
+        const lastActive = recommenderMetrics.lastActiveDate;
+        const now = new Date();
+        const inactiveDays = Math.floor(
+            (now.getTime() - lastActive.getTime()) / (1000 * 60 * 60 * 24)
+        );
+        const decayFactor = Math.pow(
+            this.DECAY_RATE,
+            Math.min(inactiveDays, this.MAX_DECAY_DAYS)
+        );
+        const decayedScore = recommenderMetrics.trustScore * decayFactor;
+        const validationTrustScore =
+            this.trustScoreDb.calculateValidationTrust(tokenAddress);
 
         return {
             tokenPerformance: {
@@ -107,6 +120,7 @@ export class TrustScoreProvider {
                 sustainedGrowth: sustainedGrowth,
                 rapidDump: isRapidDump,
                 suspiciousVolume: suspiciousVolume,
+                validationTrust: validationTrustScore,
                 lastUpdated: new Date(),
             },
             recommenderMetrics: {
@@ -118,6 +132,8 @@ export class TrustScoreProvider {
                 riskScore: recommenderMetrics.riskScore,
                 consistencyScore: recommenderMetrics.consistencyScore,
                 virtualConfidence: virtualConfidence,
+                lastActiveDate: now,
+                trustDecay: decayedScore,
                 lastUpdated: new Date(),
             },
         };
@@ -125,7 +141,8 @@ export class TrustScoreProvider {
 
     async updateRecommenderMetrics(
         recommenderId: string,
-        tokenPerformance: TokenPerformance
+        tokenPerformance: TokenPerformance,
+        recommenderWallet: string
     ): Promise<void> {
         const recommenderMetrics =
             await this.trustScoreDb.getRecommenderMetrics(recommenderId);
@@ -153,6 +170,20 @@ export class TrustScoreProvider {
             tokenPerformance,
             recommenderMetrics
         );
+
+        const balance = await this.getRecommenederBalance(recommenderWallet);
+        const virtualConfidence = balance / 1000000; // TODO: create formula to calculate virtual confidence based on user balance
+        const lastActive = recommenderMetrics.lastActiveDate;
+        const now = new Date();
+        const inactiveDays = Math.floor(
+            (now.getTime() - lastActive.getTime()) / (1000 * 60 * 60 * 24)
+        );
+        const decayFactor = Math.pow(
+            this.DECAY_RATE,
+            Math.min(inactiveDays, this.MAX_DECAY_DAYS)
+        );
+        const decayedScore = recommenderMetrics.trustScore * decayFactor;
+
         const newRecommenderMetrics: RecommenderMetrics = {
             recommenderId: recommenderId,
             trustScore: overallTrustScore,
@@ -161,7 +192,9 @@ export class TrustScoreProvider {
             avgTokenPerformance: avgTokenPerformance,
             riskScore: riskScore,
             consistencyScore: consistencyScore,
-            virtualConfidence: recommenderMetrics.virtualConfidence,
+            virtualConfidence: virtualConfidence,
+            lastActiveDate: new Date(),
+            trustDecay: decayedScore,
             lastUpdated: new Date(),
         };