{"version":3,"sources":["../src/logger.ts","../src/kv-store.ts","../src/user-stats-store.ts"],"names":["kv"],"mappings":"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","file":"user-stats-store.cjs","sourcesContent":["// Simple logger interface\nexport interface Logger {\n  info: (obj: Record<string, unknown>, msg?: string) => void;\n  error: (obj: Record<string, unknown>, msg?: string) => void;\n  warn: (obj: Record<string, unknown>, msg?: string) => void;\n  debug: (obj: Record<string, unknown>, msg?: string) => void;\n  child: (bindings: object) => Logger;\n}\n\n/**\n * Centralized logger configuration\n * \n * This provides consistent logging across all modules with proper\n * context and standardized error handling.\n */\n\n// Simple console-based logger factory - no external dependencies\nconst createLogger = (): Logger => {\n  // Get log level from environment or default to 'info'\n  const logLevel = process.env.LOG_LEVEL || 'info';\n  \n  // Map log levels to numeric values for comparison\n  const logLevels = {\n    debug: 0,\n    info: 1,\n    warn: 2,\n    error: 3\n  } as const;\n  \n  // Current log level\n  const currentLevelValue = logLevel in logLevels \n    ? logLevels[logLevel as keyof typeof logLevels] \n    : logLevels.info;\n  \n  // Format a log message with timestamp and metadata\n  const formatLog = (level: string, obj: Record<string, unknown>, msg?: string): string => {\n    const timestamp = new Date().toISOString();\n    const service = 'wisdom-sdk';\n    const objStr = JSON.stringify(obj);\n    return `[${timestamp}] ${level.toUpperCase()} [${service}] ${msg || ''} ${objStr}`;\n  };\n  \n  // Simple implementation using console methods\n  return {\n    debug: (obj: Record<string, unknown>, msg?: string) => {\n      if (currentLevelValue <= 0) { // debug level\n        console.debug(formatLog('debug', obj, msg));\n      }\n    },\n    info: (obj: Record<string, unknown>, msg?: string) => {\n      if (currentLevelValue <= 1) { // info level\n        console.info(formatLog('info', obj, msg));\n      }\n    },\n    warn: (obj: Record<string, unknown>, msg?: string) => {\n      if (currentLevelValue <= 2) { // warn level\n        console.warn(formatLog('warn', obj, msg));\n      }\n    },\n    error: (obj: Record<string, unknown>, msg?: string) => {\n      if (currentLevelValue <= 3) { // error level\n        console.error(formatLog('error', obj, msg));\n      }\n    },\n    child: (bindings: object) => {\n      // For child loggers, we merge the bindings with the log objects\n      const childLogger = createLogger();\n      \n      // Override methods to include the bindings\n      return {\n        debug: (obj: Record<string, unknown>, msg?: string) => \n          childLogger.debug({ ...obj, ...bindings }, msg),\n        info: (obj: Record<string, unknown>, msg?: string) => \n          childLogger.info({ ...obj, ...bindings }, msg),\n        warn: (obj: Record<string, unknown>, msg?: string) => \n          childLogger.warn({ ...obj, ...bindings }, msg),\n        error: (obj: Record<string, unknown>, msg?: string) => \n          childLogger.error({ ...obj, ...bindings }, msg),\n        child: (nestedBindings: object) => \n          childLogger.child({ ...bindings, ...nestedBindings })\n      };\n    }\n  };\n};\n\n// Default logger instance\nexport const logger = createLogger();\n\n// Create a child logger with context\nexport function getContextLogger(context: string): Logger {\n  return logger.child({ context });\n}\n\n// Error handling utilities\nexport class AppError extends Error {\n  public readonly context: string;\n  public readonly code: string;\n  public readonly originalError?: Error;\n  public readonly data?: Record<string, unknown>;\n\n  constructor({\n    message,\n    context = 'general',\n    code = 'INTERNAL_ERROR',\n    originalError,\n    data,\n  }: {\n    message: string;\n    context?: string;\n    code?: string;\n    originalError?: Error;\n    data?: Record<string, unknown>;\n  }) {\n    super(message);\n    this.name = 'AppError';\n    this.context = context;\n    this.code = code;\n    this.originalError = originalError;\n    this.data = data;\n    // Preserve stack trace\n    Error.captureStackTrace(this, this.constructor);\n  }\n\n  // Logs this error with appropriate context and returns it\n  log() {\n    const contextLogger = getContextLogger(this.context);\n    const logObj = {\n      code: this.code,\n      error: this.message,\n      ...(this.originalError && { originalError: this.originalError.message }),\n      ...(this.data && { data: this.data }),\n    };\n\n    contextLogger.error(logObj, this.message);\n    return this;\n  }\n}\n\nexport default logger;","import { kv } from '@vercel/kv';\nimport { AppError, logger } from './logger';\n\n/**\n * Centralized KV Store Helper\n * \n * This provides standardized methods for interacting with Vercel KV storage,\n * ensuring consistent key formats, serialization/deserialization, and error handling.\n * \n * Also provides transaction support to ensure data consistency for complex operations.\n */\n\n// Create a logger instance for this module\nconst kvLogger = logger.child({ context: 'kv-store' });\n\n// Define constant prefixes for all entity types\nexport const KV_PREFIXES = {\n  MARKET: 'market',\n  MARKET_IDS: 'market_ids',\n  USER_MARKETS: 'user_markets',\n  MARKET_PARTICIPANTS: 'market_participants',\n  MARKET_CATEGORY: 'market_category',  // Index for markets by category\n  MARKET_STATUS: 'market_status',      // Index for markets by status\n  PREDICTION: 'prediction',\n  USER_PREDICTIONS: 'user_predictions',\n  MARKET_PREDICTIONS: 'market_predictions',\n  PREDICTION_NFT: 'prediction_nft',\n  USER_BALANCE: 'user_balance',\n  USER_STATS: 'user_stats',\n  LEADERBOARD: 'leaderboard',\n  LEADERBOARD_EARNINGS: 'leaderboard_earnings',\n  LEADERBOARD_ACCURACY: 'leaderboard_accuracy',\n  BUG_REPORT: 'bug_report',\n  BUG_REPORT_IDS: 'bug_report_ids',\n  USER_BUG_REPORTS: 'user_bug_reports',\n  // Transaction custody-related prefixes\n  CUSTODY_TRANSACTION: 'custody_transaction',\n  CUSTODY_TRANSACTION_IDS: 'custody_transaction_ids',\n  USER_TRANSACTIONS: 'user_transactions',\n  SIGNER_TRANSACTIONS: 'signer_transactions',\n  MARKET_TRANSACTIONS: 'market_transactions',\n  CUSTODY_NFT_RECEIPT: 'custody_nft_receipt',\n  // Claim reward transaction prefixes\n  CLAIM_REWARD_TRANSACTION: 'claim_reward_transaction',\n  USER_CLAIM_REWARDS: 'user_claim_rewards'\n} as const;\n\n// Type safety for valid entity types\nexport type EntityType = keyof typeof KV_PREFIXES;\n\n/**\n * Get a formatted key for a specific entity\n */\nexport function getKey(entityType: EntityType, id?: string): string {\n  const prefix = KV_PREFIXES[entityType];\n\n  // Special handling for MARKET_IDS - it doesn't use a colon format\n  if (entityType === 'MARKET_IDS' && !id) {\n    return prefix;\n  }\n\n  return id ? `${prefix}:${id}` : prefix;\n}\n\n/**\n * Store an entity in KV\n */\nexport async function storeEntity<T>(entityType: EntityType, id: string, data: T): Promise<T> {\n  try {\n    const key = getKey(entityType, id);\n    await kv.set(key, JSON.stringify(data));\n    return data;\n  } catch (error) {\n    throw new AppError({\n      message: `Failed to store ${entityType} with ID ${id}`,\n      context: 'kv-store',\n      code: 'KV_STORE_ERROR',\n      originalError: error instanceof Error ? error : new Error(String(error)),\n      data: { entityType, id, operation: 'store' }\n    }).log();\n  }\n}\n\n/**\n * Get an entity from KV - with backward compatibility\n */\nexport async function getEntity<T>(entityType: EntityType, id: string): Promise<T | null> {\n  try {\n    // Try with new key format\n    const key = getKey(entityType, id);\n    let data = await kv.get<string>(key);\n\n    // If not found and it's a MARKET, try the old plural format (markets:id)\n    if (!data && entityType === 'MARKET') {\n      data = await kv.get<string>(`markets:${id}`);\n    }\n\n    if (!data) {\n      // Not an error, just not found\n      kvLogger.debug({ entityType, id }, `Entity not found: ${entityType}:${id}`);\n      return null;\n    }\n\n    // If data is already in object format (newer KV might handle JSON automatically)\n    if (typeof data !== 'string') {\n      return data as unknown as T;\n    }\n\n    // Parse JSON string\n    try {\n      return JSON.parse(data) as T;\n    } catch (e) {\n      throw new AppError({\n        message: `Error parsing JSON for ${entityType} with ID ${id}`,\n        context: 'kv-store',\n        code: 'KV_JSON_PARSE_ERROR',\n        originalError: e instanceof Error ? e : new Error(String(e)),\n        data: { entityType, id, operation: 'parse' }\n      }).log();\n    }\n  } catch (error) {\n    // Only throw AppError if it's not already one\n    if (error instanceof AppError) {\n      throw error;\n    }\n\n    throw new AppError({\n      message: `Failed to retrieve ${entityType} with ID ${id}`,\n      context: 'kv-store',\n      code: 'KV_RETRIEVE_ERROR',\n      originalError: error instanceof Error ? error : new Error(String(error)),\n      data: { entityType, id, operation: 'get' }\n    }).log();\n  }\n}\n\n/**\n * Delete an entity from KV\n */\nexport async function deleteEntity(entityType: EntityType, id: string): Promise<boolean> {\n  try {\n    const key = getKey(entityType, id);\n    await kv.del(key);\n\n    // If it's a MARKET, also try to delete the legacy format\n    if (entityType === 'MARKET') {\n      await kv.del(`markets:${id}`);\n    }\n\n    return true;\n  } catch (error) {\n    // Log error but don't throw - deletion errors are often non-critical\n    new AppError({\n      message: `Failed to delete ${entityType} with ID ${id}`,\n      context: 'kv-store',\n      code: 'KV_DELETE_ERROR',\n      originalError: error instanceof Error ? error : new Error(String(error)),\n      data: { entityType, id, operation: 'delete' }\n    }).log();\n\n    return false;\n  }\n}\n\n/**\n * Add an ID to a set - with backward compatibility\n */\nexport async function addToSet(setType: EntityType, id: string, memberId: string): Promise<boolean> {\n  try {\n    const key = getKey(setType, id);\n    await kv.sadd(key, memberId);\n\n    // If it's MARKET_IDS, also add to the old format for backward compatibility\n    if (setType === 'MARKET_IDS') {\n      await kv.sadd('market_ids', memberId);\n    }\n\n    return true;\n  } catch (error) {\n    new AppError({\n      message: `Failed to add member ${memberId} to set ${setType}:${id}`,\n      context: 'kv-store',\n      code: 'KV_SET_ADD_ERROR',\n      originalError: error instanceof Error ? error : new Error(String(error)),\n      data: { setType, id, memberId, operation: 'sadd' }\n    }).log();\n\n    return false;\n  }\n}\n\n/**\n * Remove an ID from a set\n */\nexport async function removeFromSet(setType: EntityType, id: string, memberId: string): Promise<boolean> {\n  try {\n    const key = getKey(setType, id);\n    await kv.srem(key, memberId);\n\n    // If it's MARKET_IDS, also remove from the old format for backward compatibility\n    if (setType === 'MARKET_IDS') {\n      await kv.srem('market_ids', memberId);\n    }\n\n    return true;\n  } catch (error) {\n    new AppError({\n      message: `Failed to remove member ${memberId} from set ${setType}:${id}`,\n      context: 'kv-store',\n      code: 'KV_SET_REMOVE_ERROR',\n      originalError: error instanceof Error ? error : new Error(String(error)),\n      data: { setType, id, memberId, operation: 'srem' }\n    }).log();\n\n    return false;\n  }\n}\n\n/**\n * Get all members of a set - with backward compatibility\n */\nexport async function getSetMembers(setType: EntityType, id: string): Promise<string[]> {\n  try {\n    const key = getKey(setType, id);\n    let members = await kv.smembers(key) as string[];\n\n    // For backward compatibility with market_ids\n    if (setType === 'MARKET_IDS' && members.length === 0) {\n      const legacyMembers = await kv.smembers('market_ids') as string[];\n      if (legacyMembers.length > 0) {\n        // Migrate the data to the new format\n        for (const marketId of legacyMembers) {\n          await addToSet('MARKET_IDS', '', marketId);\n        }\n        members = legacyMembers;\n      }\n    }\n\n    return members;\n  } catch (error) {\n    new AppError({\n      message: `Failed to get members from set ${setType}:${id}`,\n      context: 'kv-store',\n      code: 'KV_SET_MEMBERS_ERROR',\n      originalError: error instanceof Error ? error : new Error(String(error)),\n      data: { setType, id, operation: 'smembers' }\n    }).log();\n\n    return [];\n  }\n}\n\n/**\n * Check if a member is in a set\n */\nexport async function isSetMember(setType: EntityType, id: string, memberId: string): Promise<boolean> {\n  try {\n    const key = getKey(setType, id);\n    const result = await kv.sismember(key, memberId);\n    return !!result;\n  } catch (error) {\n    console.error(`Error checking set membership for ${setType} with ID ${id}:`, error);\n    return false;\n  }\n}\n\n/**\n * Add a member to a sorted set with score\n */\nexport async function addToSortedSet(setType: EntityType, memberId: string, score: number): Promise<boolean> {\n  try {\n    const key = getKey(setType);\n    await kv.zadd(key, { score, member: memberId });\n    return true;\n  } catch (error) {\n    console.error(`Error adding to sorted set ${setType}:`, error);\n    return false;\n  }\n}\n\n/**\n * Get top members from a sorted set\n */\nexport async function getTopFromSortedSet(setType: EntityType, limit: number = 10, reverse: boolean = true): Promise<string[]> {\n  try {\n    const key = getKey(setType);\n    return await kv.zrange(key, 0, limit - 1, { rev: reverse }) as string[];\n  } catch (error) {\n    console.error(`Error getting top members from sorted set ${setType}:`, error);\n    return [];\n  }\n}\n\n/**\n * Get scores for specific members from a sorted set\n * Returns a map of memberId -> score\n */\nexport async function getScoresFromSortedSet(setType: EntityType, memberIds: string[]): Promise<Record<string, number>> {\n  try {\n    const key = getKey(setType);\n    const result: Record<string, number> = {};\n\n    // Process members in batches if there are many\n    const batchSize = 50;\n    for (let i = 0; i < memberIds.length; i += batchSize) {\n      const batch = memberIds.slice(i, i + batchSize);\n\n      // Get scores for this batch\n      const batchScores = await Promise.all(\n        batch.map(async (memberId) => {\n          const score = await kv.zscore(key, memberId);\n          return { memberId, score: score ? Number(score) : null };\n        })\n      );\n\n      // Add scores to result map\n      batchScores.forEach(({ memberId, score }) => {\n        if (score !== null) {\n          result[memberId] = score;\n        }\n      });\n    }\n\n    return result;\n  } catch (error) {\n    console.error(`Error getting scores from sorted set ${setType}:`, error);\n    return {};\n  }\n}\n\n/**\n * Get all keys matching a pattern\n */\nexport async function getKeys(pattern: string): Promise<string[]> {\n  try {\n    return await kv.keys(pattern) as string[];\n  } catch (error) {\n    console.error(`Error getting keys with pattern ${pattern}:`, error);\n    return [];\n  }\n}\n\n/**\n * Check if a key exists\n */\nexport async function keyExists(entityType: EntityType, id: string): Promise<boolean> {\n  try {\n    const key = getKey(entityType, id);\n    const result = await kv.exists(key);\n    return result === 1;\n  } catch (error) {\n    console.error(`Error checking if key exists for ${entityType} with ID ${id}:`, error);\n    return false;\n  }\n}\n\n/**\n * Debug function to get information about KV store\n */\nexport async function getDebugInfo(): Promise<Record<string, unknown>> {\n  try {\n    const allKeys = await kv.keys('*');\n    const patterns = [\n      'market:*',\n      'markets:*',\n      'market_ids',\n      'prediction:*',\n      'predictions:*',\n      'user_predictions:*',\n      'market_predictions:*',\n      'prediction_nft:*',\n      'prediction_nfts:*'\n    ];\n\n    const result: Record<string, unknown> = {\n      totalKeys: allKeys.length,\n      keysByPattern: {} as Record<string, { count: number; sample: string[] }>\n    };\n\n    const keysByPattern = result.keysByPattern as Record<string, { count: number; sample: string[] }>;\n\n    for (const pattern of patterns) {\n      const keys = await kv.keys(pattern);\n      keysByPattern[pattern] = {\n        count: keys.length,\n        sample: keys.slice(0, 5) as string[]\n      };\n    }\n\n    return result;\n  } catch (error) {\n    console.error('Error getting debug info:', error);\n    return { error: String(error) };\n  }\n}\n\n/**\n * Transaction interface for atomic operations\n */\nexport interface KvTransaction {\n  operations: Array<{\n    type: 'entity' | 'set' | 'sortedSet';\n    entityType: EntityType;\n    id: string;\n    data?: unknown;\n  }>;\n  addEntity<T>(entityType: EntityType, id: string, data: T): Promise<void>;\n  addToSetInTransaction(setType: EntityType, id: string, memberId: string): Promise<void>;\n  addToSortedSetInTransaction(setType: EntityType, memberId: string, score: number): Promise<void>;\n  execute(): Promise<boolean>;\n}\n\n/**\n * Start a Redis transaction for atomic operations\n * @returns A transaction object with methods that queue commands to be executed atomically\n */\nexport async function startTransaction(): Promise<KvTransaction> {\n  try {\n    // @vercel/kv supports Redis transactions via the multi() method\n    const transaction = kv.multi();\n\n    // Track operations for potential rollback planning\n    const operations: Array<{\n      type: 'entity' | 'set' | 'sortedSet';\n      entityType: EntityType;\n      id: string;\n      data?: unknown;\n    }> = [];\n\n    const txObject: KvTransaction = {\n      operations,\n\n      // Add entity to transaction\n      async addEntity<T>(entityType: EntityType, id: string, data: T): Promise<void> {\n        const key = getKey(entityType, id);\n        transaction.set(key, JSON.stringify(data));\n        operations.push({ type: 'entity', entityType, id, data });\n      },\n\n      // Add to set in transaction\n      async addToSetInTransaction(setType: EntityType, id: string, memberId: string): Promise<void> {\n        const key = getKey(setType, id);\n        transaction.sadd(key, memberId);\n        operations.push({ type: 'set', entityType: setType, id: memberId });\n\n        // Handle backward compatibility if needed\n        if (setType === 'MARKET_IDS') {\n          transaction.sadd('market_ids', memberId);\n        }\n      },\n\n      // Add to sorted set in transaction\n      async addToSortedSetInTransaction(setType: EntityType, memberId: string, score: number): Promise<void> {\n        const key = getKey(setType);\n        transaction.zadd(key, { score, member: memberId });\n        operations.push({ type: 'sortedSet', entityType: setType, id: memberId, data: score });\n      },\n\n      // Execute all queued commands atomically\n      async execute(): Promise<boolean> {\n        try {\n          kvLogger.debug(\n            { operationCount: operations.length },\n            `Executing transaction with ${operations.length} operations`\n          );\n\n          await transaction.exec();\n          return true;\n        } catch (error) {\n          const appError = new AppError({\n            message: 'Transaction execution failed',\n            context: 'kv-store',\n            code: 'TRANSACTION_FAILED',\n            originalError: error instanceof Error ? error : new Error(String(error)),\n            data: { operationCount: operations.length }\n          });\n\n          appError.log();\n\n          // Note: Redis transactions are atomic - they either all succeed or all fail\n          // No manual rollback is needed as failed transactions don't apply any changes\n\n          return false;\n        }\n      }\n    };\n\n    return txObject;\n  } catch (error) {\n    throw new AppError({\n      message: 'Failed to start transaction',\n      context: 'kv-store',\n      code: 'TRANSACTION_START_ERROR',\n      originalError: error instanceof Error ? error : new Error(String(error))\n    }).log();\n  }\n}","import * as kvStore from './kv-store';\n\n// User stats store with Vercel KV\nexport const userStatsStore = {\n  // Helper to calculate user score consistently across the app\n  calculateUserScore(stats: any): number {\n    // Only count users with at least 5 predictions for the accuracy component\n    const accuracyComponent = stats.totalPredictions >= 5 ? stats.accuracy : 0;\n\n    // Normalize earnings (0-100 scale typically)\n    const normalizedEarnings = stats.totalEarnings / 100;\n\n    // Prediction volume factor (logarithmic scale to prevent domination by volume)\n    const volumeFactor = stats.totalPredictions > 0 ? Math.log10(stats.totalPredictions + 1) * 10 : 0;\n\n    // Consistency factor - higher for users who maintain accuracy across more predictions\n    const consistencyFactor = stats.totalPredictions >= 10 ?\n      (accuracyComponent * Math.min(stats.totalPredictions / 20, 1.5)) :\n      accuracyComponent;\n\n    // Final composite score\n    return (consistencyFactor * 0.4) +\n      (normalizedEarnings * 0.3) +\n      (Math.min(volumeFactor, 25) * 0.3);\n  },\n\n  // Get user stats for a specific user\n  async getUserStats(userId: string) {\n    try {\n      if (!userId) return null;\n\n      const stats = await kvStore.getEntity('USER_STATS', userId);\n      return stats || null;\n    } catch (error) {\n      console.error(`Error getting user stats for ${userId}:`, error);\n      return null;\n    }\n  },\n\n  // Update user stats when a prediction is made\n  async updateStatsForNewPrediction(userId: string, prediction: any) {\n    try {\n      // Get current stats or create new ones\n      const currentStats: any = await this.getUserStats(userId) || {\n        userId,\n        totalPredictions: 0,\n        correctPredictions: 0,\n        accuracy: 0,\n        totalAmount: 0,\n        totalEarnings: 0,\n        lastUpdated: new Date().toISOString()\n      };\n\n      // Update stats\n      const updatedStats = {\n        ...currentStats,\n        totalPredictions: currentStats.totalPredictions + 1,\n        totalAmount: currentStats.totalAmount + prediction.amount,\n        lastUpdated: new Date().toISOString()\n      };\n\n      // Recalculate accuracy\n      updatedStats.accuracy =\n        updatedStats.totalPredictions > 0\n          ? (updatedStats.correctPredictions / updatedStats.totalPredictions) * 100\n          : 0;\n\n      // Store updated stats\n      await kvStore.storeEntity('USER_STATS', userId, updatedStats);\n\n      // Update leaderboard sorted sets for efficient querying\n      await this.updateLeaderboardEntries(updatedStats);\n\n      return updatedStats;\n    } catch (error) {\n      console.error(`Error updating stats for user ${userId}:`, error);\n      throw error;\n    }\n  },\n\n  // Update user stats when a prediction is resolved\n  async updateStatsForResolvedPrediction(\n    userId: string,\n    prediction: any,\n    isCorrect: boolean,\n    earnings: number\n  ) {\n    try {\n      // Handle anonymous/test users specially\n      if (!userId || userId === 'anonymous') {\n        console.log('Skipping stats update for anonymous user');\n        return {\n          userId,\n          totalPredictions: 1,\n          correctPredictions: isCorrect ? 1 : 0,\n          accuracy: isCorrect ? 100 : 0,\n          totalAmount: prediction?.amount || 0,\n          totalEarnings: earnings,\n          lastUpdated: new Date().toISOString()\n        };\n      }\n\n      // Get current stats\n      const currentStats: any = await this.getUserStats(userId);\n      if (!currentStats) {\n        console.log(`Creating new stats for user ${userId}`);\n        // Create default stats if not found\n        const newStats = {\n          userId,\n          totalPredictions: 1,\n          correctPredictions: isCorrect ? 1 : 0,\n          accuracy: isCorrect ? 100 : 0,\n          totalAmount: prediction?.amount || 0,\n          totalEarnings: earnings,\n          lastUpdated: new Date().toISOString()\n        };\n        \n        // Store new stats\n        await kvStore.storeEntity('USER_STATS', userId, newStats);\n        \n        // Update leaderboard sorted sets\n        await this.updateLeaderboardEntries(newStats);\n        \n        return newStats;\n      }\n\n      // Update stats\n      const updatedStats = {\n        ...currentStats,\n        correctPredictions: isCorrect\n          ? currentStats.correctPredictions + 1\n          : currentStats.correctPredictions,\n        totalEarnings: currentStats.totalEarnings + earnings,\n        lastUpdated: new Date().toISOString()\n      };\n\n      // Recalculate accuracy\n      updatedStats.accuracy =\n        updatedStats.totalPredictions > 0\n          ? (updatedStats.correctPredictions / updatedStats.totalPredictions) * 100\n          : 0;\n\n      // Store updated stats\n      await kvStore.storeEntity('USER_STATS', userId, updatedStats);\n\n      // Update leaderboard sorted sets\n      await this.updateLeaderboardEntries(updatedStats);\n\n      return updatedStats;\n    } catch (error) {\n      console.error(`Error updating stats for resolved prediction, user ${userId}:`, error);\n      throw error;\n    }\n  },\n\n  // Update user's username (when available from auth provider)\n  async updateUsername(userId: string, username: string) {\n    try {\n      const stats: any = await this.getUserStats(userId);\n      if (!stats) return null;\n\n      const updatedStats = {\n        ...stats,\n        username,\n        lastUpdated: new Date().toISOString()\n      };\n\n      await kvStore.storeEntity('USER_STATS', userId, updatedStats);\n\n      // Update leaderboard entries\n      await this.updateLeaderboardEntries(updatedStats);\n\n      return updatedStats;\n    } catch (error) {\n      console.error(`Error updating username for user ${userId}:`, error);\n      return null;\n    }\n  },\n\n  // Update leaderboard sorted sets for efficient querying\n  async updateLeaderboardEntries(stats: any): Promise<void> {\n    try {\n      // Add to earnings leaderboard (sorted by total earnings)\n      await kvStore.addToSortedSet(\n        'LEADERBOARD_EARNINGS',\n        stats.userId,\n        stats.totalEarnings\n      );\n\n      // Add to accuracy leaderboard (sorted by accuracy)\n      // Only count users with at least 5 predictions for accuracy\n      const accuracyScore = stats.totalPredictions >= 5 ? stats.accuracy : 0;\n      await kvStore.addToSortedSet(\n        'LEADERBOARD_ACCURACY',\n        stats.userId,\n        accuracyScore\n      );\n\n      // Advanced scoring algorithm for leaderboard ranking\n      // Calculate the composite score using the helper method\n      const compositeScore = this.calculateUserScore(stats);\n\n      // Store in the main leaderboard\n      await kvStore.addToSortedSet(\n        'LEADERBOARD',\n        stats.userId,\n        compositeScore\n      );\n    } catch (error) {\n      console.error('Error updating leaderboard entries:', error);\n      throw error;\n    }\n  },\n\n  // Get top leaderboard entries by earnings\n  async getTopEarners(limit: number = 10) {\n    try {\n      // Get top user IDs sorted by earnings (highest first)\n      const userIds = await kvStore.getTopFromSortedSet('LEADERBOARD_EARNINGS', limit);\n\n      // Get full stats for each user ID\n      const leaderboard = await this.getUserStatsForIds(userIds);\n\n      // Get scores from the same sorted set to ensure consistency\n      const scoresMap = await kvStore.getScoresFromSortedSet('LEADERBOARD_EARNINGS', userIds);\n\n      // Add rank and use the actual scores from Redis\n      return leaderboard.map((entry: any, index) => {\n        return {\n          ...entry,\n          rank: index + 1,\n          score: scoresMap[entry.userId] || this.calculateUserScore(entry)\n        };\n      });\n    } catch (error) {\n      console.error('Error getting top earners:', error);\n      return [];\n    }\n  },\n\n  // Get top leaderboard entries by accuracy\n  async getTopAccurate(limit: number = 10) {\n    try {\n      // Get top user IDs sorted by accuracy (highest first)\n      const userIds = await kvStore.getTopFromSortedSet('LEADERBOARD_ACCURACY', limit);\n\n      // Get full stats for each user ID\n      const leaderboard = await this.getUserStatsForIds(userIds);\n\n      // Get scores from the same sorted set to ensure consistency\n      const scoresMap = await kvStore.getScoresFromSortedSet('LEADERBOARD_ACCURACY', userIds);\n\n      // Add rank and use the actual scores from Redis\n      return leaderboard.map((entry: any, index) => {\n        return {\n          ...entry,\n          rank: index + 1,\n          score: scoresMap[entry.userId] || this.calculateUserScore(entry)\n        };\n      });\n    } catch (error) {\n      console.error('Error getting top accuracy:', error);\n      return [];\n    }\n  },\n\n  // Get top leaderboard entries by combined score\n  async getTopUsers(limit: number = 10) {\n    try {\n      // Get top user IDs sorted by combined score (highest first)\n      const userIds = await kvStore.getTopFromSortedSet('LEADERBOARD', limit);\n\n      // Get full stats for each user ID\n      const leaderboard = await this.getUserStatsForIds(userIds);\n\n      // Get scores from the same sorted set to ensure consistency\n      const scoresMap = await kvStore.getScoresFromSortedSet('LEADERBOARD', userIds);\n\n      // Add rank and use the actual scores from Redis\n      return leaderboard.map((entry: any, index) => {\n        return {\n          ...entry,\n          rank: index + 1,\n          score: scoresMap[entry.userId] || this.calculateUserScore(entry)\n        };\n      });\n    } catch (error) {\n      console.error('Error getting leaderboard:', error);\n      return [];\n    }\n  },\n\n  // Helper to get multiple user stats by IDs\n  async getUserStatsForIds(userIds: string[]) {\n    try {\n      if (userIds.length === 0) return [];\n\n      // Get stats for each user ID\n      const statsPromises = userIds.map(id => this.getUserStats(id));\n      const statsResults = await Promise.all(statsPromises);\n\n      // Filter out any null results\n      return statsResults.filter(Boolean);\n    } catch (error) {\n      console.error('Error getting user stats for IDs:', error);\n      return [];\n    }\n  }\n};"]}