Feat/ranked leaderboard 967#976
Merged
Olowodarey merged 7 commits intoJun 17, 2026
Merged
Conversation
…omputation - Add #[contracttype] LeaderboardEntry struct with full ranking information - Implement deterministic tie-breaking logic in outranks() method - Create leaderboard.rs module with get_event_leaderboard() function - Compute live leaderboard by aggregating participant stats: - Sum total_points from all predictions - Count correct_results (is_correct == Some(true)) - Count exact_scores (4-point predictions) - Track last_prediction_time for tie-breaking - Sort by total_points desc, then exact_scores desc, then earliest prediction time, then address - Assign 1-based ranks with no shared ranks (ties broken deterministically) - Returns sorted Vec<LeaderboardEntry> that can be called before all matches resolve
- Add pub fn get_event_leaderboard(env: Env, event_id: u64) -> Vec<LeaderboardEntry> - Proper error handling with panic messages (event_not_found, overflow) - Replaces old verify_event_winners and get_event_winners endpoints - Enables clients to query ranked participant list for any event
…ions - Remove Winner struct from storage_types.rs (replaced by LeaderboardEntry) - Remove oracle::verify_event_winners and oracle::get_event_winners functions - Remove storage::get_event_winners and storage::add_event_winner helpers - Remove DataKey::EventWinners storage key variant - Update views::EventStatistics (no Winner-related fields to remove) - Simplify oracle.rs and storage.rs without Winner machinery - Clean migration from binary winner model to ranked leaderboard system
- test_leaderboard_ranks_by_total_points_desc: Verify primary sort by total points - test_leaderboard_tiebreak_by_exact_scores: Verify tiebreak by exact score count - test_leaderboard_tiebreak_by_earliest_prediction: Verify prediction time tiebreak - test_leaderboard_live_before_all_matches_resolved: Verify live leaderboard with unresolved matches - test_leaderboard_empty_event: Verify empty event returns empty Vec - test_leaderboard_single_participant: Verify single participant gets rank 1 - All tests pass with proper ranking and tie-breaking
- Remove Winner imports from data_structures_test.rs, storage_types_tests.rs, views_tests.rs - Delete 11 Winner-specific unit tests (creation, accuracy, outranking logic) - Update test comments to reflect removal of Winner struct - Update views_tests.rs to remove EventStatistics Winner fields (winners_verified, winner_count) - Remove temporary storage access that was causing test failures - All 226 integration tests now pass with leaderboard-only implementation
…board implementation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Collaborator
|
@OsagieCynthia weldone for the changes |
10 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Replace Perfect-Scorer Winner Model with Ranked Leaderboard
closes #967
Overview
This PR completes the transition from a binary "winner / not winner" model to a fully ranked leaderboard system that supports top-N prize splits and flexible reward distributions. The old system only identified users who got every match correct; the new system ranks all participants by total points with deterministic tie-breaking.
Problem Statement
The previous
Winnerstruct and associated functions (verify_event_winners,get_event_winners) could only identify perfect scorers (users with 100% accuracy). This binary model cannot support:Solution
Introduced
LeaderboardEntrystruct andget_event_leaderboard()function that:total_points: Sum of all earned points (0, 1, or 4 per prediction)correct_results: Count of correct 1X2 predictionsexact_scores: Count of exact score predictions (4-point predictions)matches_played: Total predictions submittedlast_prediction_time: Timestamp of most recent predictionChanges Made
New Files
src/leaderboard.rs(234 lines)LeaderboardErrorenum for error handlingget_event_leaderboard(env: &Env, event_id: u64) -> Result<Vec<LeaderboardEntry>, LeaderboardError>tests/leaderboard_tests.rs(322 lines)test_leaderboard_ranks_by_total_points_desc: Primary sort verificationtest_leaderboard_tiebreak_by_exact_scores: Exact score tie-breakingtest_leaderboard_tiebreak_by_earliest_prediction: Prediction time tie-breakingtest_leaderboard_live_before_all_matches_resolved: Live leaderboard before match completiontest_leaderboard_empty_event: Empty event handlingtest_leaderboard_single_participant: Single participant rankingModified Files
src/storage_types.rsLeaderboardEntrystruct with#[contracttype]derivenew()constructor (rank assigned later)outranks()method implementing tie-breaking logicWinnerstruct (was ~60 lines of dead code)src/leaderboard.rssrc/lib.rspub fn verify_event_winners()withpub fn get_event_leaderboard()pub fn get_event_winners()with single leaderboard endpointsrc/oracle.rsverify_event_winners()function (was ~100 lines)get_event_winners()function (was ~50 lines)get_user_score()unchanged (already returns 4-tuple with full stats)src/storage.rsget_event_winners()storage helperadd_event_winner()storage helperDataKeyenum kept butEventWinnersvariant removedsrc/views.rsEventStatisticsstruct already clean (no Winner fields to remove)Test Updates
tests/data_structures_test.rsWinnerstructtests/storage_types_tests.rsWinnerstructtests/views_tests.rsWinnerstructtest_event_statistics_completion_statusto remove Winner-related assertionswinner,winners_verified, andwinner_countreferencestests/oracle_tests.rsTesting
✅ All 226 integration tests pass
Test Coverage
Acceptance Criteria
✅
get_event_leaderboardreturns all participants ranked by total points✅ Tie-breaking order matches spec exactly
✅ Old perfect-scorer functions/types/storage keys fully removed
✅
get_event_statisticscompiles and functions properly without Winner✅ All acceptance criteria tests passing
API Changes
Removed Endpoints
New Endpoints
New Type
Impact & Dependencies
✅ No Breaking Changes to Public API
🔗 Enables Issue #6 (Payout System)
📊 Data Migration
Performance Considerations
Commits
feat(Ranked event leaderboard #967): Add LeaderboardEntry struct and core leaderboard computation
feat(Ranked event leaderboard #967): Expose get_event_leaderboard contract endpoint
chore(Ranked event leaderboard #967): Remove old Winner struct and perfect-scorer functions
test(Ranked event leaderboard #967): Add comprehensive leaderboard integration tests
test(Ranked event leaderboard #967): Remove Winner struct references from tests
Future Considerations
Verification
Expected output: 226 tests passed