diff --git a/contracts/src/wager/types.cairo b/contracts/src/wager/types.cairo index 48acc75..2257adc 100644 --- a/contracts/src/wager/types.cairo +++ b/contracts/src/wager/types.cairo @@ -52,3 +52,83 @@ pub enum WagerState { Resolved, Cancelled } + +#[derive(Copy, Drop, Serde)] +pub struct Achievement { + pub achievement_type: AchievementType, + pub earned_at: u64, + pub wager_id: u64, +} + +#[derive(Copy, Drop, Serde, PartialEq)] +pub enum AchievementType { + FirstWager, // Created first wager + FirstWin, // Won first wager + FirstJoin, // Joined first wager + WinStreak5, // 5 consecutive wins + WinStreak10, // 10 consecutive wins + AccuratePrediction, // 80%+ accuracy over 10 wagers + HighStaker, // Placed wager worth 1000+ STRK + FrequentPlayer, // Participated in 50+ wagers + WealthyWinner, // Won 10,000+ STRK total + QuickWinner, // Won within first 24 hours of wager creation +} + +#[derive(Copy, Drop, Serde)] +pub struct UserStats { + pub total_wagers_created: u64, + pub total_wagers_joined: u64, + pub total_wins: u64, + pub total_losses: u64, + pub current_win_streak: u64, + pub best_win_streak: u64, + pub total_volume_wagered: u256, + pub total_winnings: u256, + pub accuracy_percentage: u64, // percentage (0-100) +} + +impl AchievementTypeIntoFelt252 of Into { + fn into(self: AchievementType) -> felt252 { + match self { + AchievementType::FirstWager => 'FIRSTWAGER', + AchievementType::FirstWin => 'FIRSTWIN', + AchievementType::FirstJoin => 'FIRSTJOIN', + AchievementType::WinStreak5 => 'WINSTREAK5', + AchievementType::WinStreak10 => 'WINSTREAK10', + AchievementType::AccuratePrediction => 'ACCURATEPREDICTION', + AchievementType::HighStaker => 'HIGHSTAKER', + AchievementType::FrequentPlayer => 'FREQUENTPLAYER', + AchievementType::WealthyWinner => 'WEALTHYWINNER', + AchievementType::QuickWinner => 'QUICKWINNER', + } + } +} + +impl Felt252TryIntoAchievementType of TryInto { + fn try_into(self: felt252) -> Option { + if self == 'FIRSTWAGER' { + Option::Some(AchievementType::FirstWager) + } else if self == 'FIRSTWIN' { + Option::Some(AchievementType::FirstWin) + } else if self == 'FIRSTJOIN' { + Option::Some(AchievementType::FirstJoin) + } else if self == 'WINSTREAK5' { + Option::Some(AchievementType::WinStreak5) + } else if self == 'WINSTREAK10' { + Option::Some(AchievementType::WinStreak10) + } else if self == 'ACCURATEPREDICTION' { + Option::Some(AchievementType::AccuratePrediction) + } else if self == 'HIGHSTAKER' { + Option::Some(AchievementType::HighStaker) + } else if self == 'FREQUENTPLAYER' { + Option::Some(AchievementType::FrequentPlayer) + } else if self == 'WEALTHYWINNER' { + Option::Some(AchievementType::WealthyWinner) + } else if self == 'QUICKWINNER' { + Option::Some(AchievementType::QuickWinner) + } else { + Option::None + } + } +} + diff --git a/contracts/src/wager/wager.cairo b/contracts/src/wager/wager.cairo index 250d6bd..e708e16 100644 --- a/contracts/src/wager/wager.cairo +++ b/contracts/src/wager/wager.cairo @@ -12,7 +12,9 @@ pub mod StrkWager { use starknet::get_block_timestamp; use contracts::wager::interface::IStrkWager; - use contracts::wager::types::{Wager, Category, Mode, Claim, WagerState}; + use contracts::wager::types::{ + Wager, Category, Mode, Claim, WagerState, AchievementType, Achievement, UserStats + }; use openzeppelin::introspection::src5::SRC5Component; use openzeppelin::access::accesscontrol::{AccessControlComponent}; use openzeppelin::token::erc20::interface::{IERC20Dispatcher, IERC20DispatcherTrait}; @@ -50,6 +52,10 @@ pub mod StrkWager { accesscontrol: AccessControlComponent::Storage, #[substorage(v0)] src5: SRC5Component::Storage, + // Reputation system storage + user_stats: Map, + user_achievements: Map>, + user_achievement_count: Map, } #[event]