85 lines
2.8 KiB
Solidity
85 lines
2.8 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity ^0.8.20;
|
|
|
|
/**
|
|
* @title NaddieJump
|
|
* @notice On-chain leaderboard and reward contract for Naddie Jump game.
|
|
* @dev Designed for Monad EVM compatibility.
|
|
*/
|
|
contract NaddieJump {
|
|
struct Score {
|
|
address player;
|
|
uint256 score;
|
|
uint256 blockHeight;
|
|
uint256 timestamp;
|
|
}
|
|
|
|
mapping(address => Score) public bestScores;
|
|
Score[] public leaderboard;
|
|
uint256 public constant LEADERBOARD_SIZE = 50;
|
|
uint256 public constant REWARD_THRESHOLD = 50000;
|
|
|
|
event ScoreSubmitted(address indexed player, uint256 score, uint256 blockHeight);
|
|
event RewardClaimed(address indexed player, uint256 amount);
|
|
|
|
function submitScore(uint256 score, uint256 blockHeight) external {
|
|
require(score > 0, "Invalid score");
|
|
|
|
Score storage current = bestScores[msg.sender];
|
|
if (score > current.score) {
|
|
current.player = msg.sender;
|
|
current.score = score;
|
|
current.blockHeight = blockHeight;
|
|
current.timestamp = block.timestamp;
|
|
_updateLeaderboard(current);
|
|
}
|
|
|
|
emit ScoreSubmitted(msg.sender, score, blockHeight);
|
|
}
|
|
|
|
function _updateLeaderboard(Score memory newScore) internal {
|
|
// Simple insertion sort approach for leaderboard
|
|
bool exists = false;
|
|
for (uint256 i = 0; i < leaderboard.length; i++) {
|
|
if (leaderboard[i].player == newScore.player) {
|
|
leaderboard[i] = newScore;
|
|
exists = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!exists && leaderboard.length < LEADERBOARD_SIZE) {
|
|
leaderboard.push(newScore);
|
|
}
|
|
// Sort descending by score (bubble sort for simplicity in prototype)
|
|
for (uint256 i = 0; i < leaderboard.length; i++) {
|
|
for (uint256 j = i + 1; j < leaderboard.length; j++) {
|
|
if (leaderboard[j].score > leaderboard[i].score) {
|
|
Score memory tmp = leaderboard[i];
|
|
leaderboard[i] = leaderboard[j];
|
|
leaderboard[j] = tmp;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function getLeaderboard(uint256 count) external view returns (Score[] memory) {
|
|
uint256 len = count > leaderboard.length ? leaderboard.length : count;
|
|
Score[] memory result = new Score[](len);
|
|
for (uint256 i = 0; i < len; i++) {
|
|
result[i] = leaderboard[i];
|
|
}
|
|
return result;
|
|
}
|
|
|
|
function getPlayerBest(address player) external view returns (Score memory) {
|
|
return bestScores[player];
|
|
}
|
|
|
|
// Placeholder for future ERC-20 reward integration
|
|
function claimReward() external view returns (bool eligible) {
|
|
Score storage s = bestScores[msg.sender];
|
|
eligible = s.score >= REWARD_THRESHOLD;
|
|
// TODO: mint/transfer ERC-20 $GWEI tokens
|
|
}
|
|
}
|