Blockchain / Global / Address
Contract
0x35a7f3eE9A2b5fdEE717099F9253Ae90e1248AE3
- Balance
- 0.062 SOMI
- Transactions sent
- 1
- Type
- Contract · 3,449 bytes of code
PacmanLeaderboard Verified
- Compiler
- solc 0.8.20+commit.a1b79de6
- Language
- Solidity
- Optimization
- Yes, 200 runs
- EVM version
- —
- License
- —
- Verified
- 2026-10-12
PacmanLeaderboard.sol
Solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract PacmanLeaderboard {
address public owner;
address public treasury; // Alamat untuk menerima biaya game
uint256 public startFeeWei;
uint256 public maxScorePerSubmit;
struct Player {
uint256 totalScore;
uint256 lastPlayed;
}
mapping(address => Player) public players;
// STORAGE BARU: Array tetap 10 slot untuk leaderboard yang efisien gas
address[10] public top10Wallets;
uint256[10] public top10Scores;
event GameStarted(address indexed player, uint256 fee);
event ScoreSubmitted(address indexed player, uint256 score);
event FeeUpdated(uint256 newFee);
event MaxScoreUpdated(uint256 newMaxScore);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
event Withdraw(address indexed to, uint256 amount);
constructor(
address _treasury,
uint256 _startFeeWei,
uint256 _maxScorePerSubmit
) {
// Owner default adalah yang melakukan deploy (msg.sender)
owner = msg.sender;
treasury = _treasury;
startFeeWei = _startFeeWei;
maxScorePerSubmit = _maxScorePerSubmit;
}
modifier onlyOwner() {
require(msg.sender == owner, "Not owner");
_;
}
// Fungsi internal untuk memasukkan skor baru ke dalam Top 10 secara efisien
function _updateTop10(address player, uint256 newTotalScore) internal {
int256 insertIndex = -1;
// 1. Cari posisi yang cocok (skor lebih besar dari skor di slot tersebut)
for (uint256 i = 0; i < 10; i++) {
if (newTotalScore > top10Scores[i]) {
insertIndex = int256(i);
break;
} else if (top10Wallets[i] == player) {
// Jika pemain sudah ada di Top 10, update skor dan sortir ulang
top10Scores[i] = newTotalScore;
_sortTop10();
return;
}
}
// 2. Jika skor baru cukup tinggi untuk masuk Top 10
if (insertIndex != -1) {
// Geser entri yang lebih rendah ke bawah
for (int256 i = 9; i > insertIndex; i--) {
top10Scores[uint256(i)] = top10Scores[uint256(i - 1)];
top10Wallets[uint256(i)] = top10Wallets[uint256(i - 1)];
}
// Masukkan skor baru
top10Scores[uint256(insertIndex)] = newTotalScore;
top10Wallets[uint256(insertIndex)] = player;
}
}
// Helper: Sortir ulang array 10 item
function _sortTop10() internal {
for (uint256 i = 0; i < 10; i++) {
for (uint256 j = i + 1; j < 10; j++) {
if (top10Scores[j] > top10Scores[i]) {
(top10Scores[i], top10Scores[j]) = (top10Scores[j], top10Scores[i]);
(top10Wallets[i], top10Wallets[j]) = (top10Wallets[j], top10Wallets[i]);
}
}
}
}
function startGame() external payable {
require(msg.value == startFeeWei, "Wrong game fee");
players[msg.sender].lastPlayed = block.timestamp;
emit GameStarted(msg.sender, msg.value);
}
function submitScore(uint256 score) external {
require(score <= maxScorePerSubmit, "Score too high");
require(players[msg.sender].lastPlayed != 0, "Start game first");
// Akumulasi total skor pemain
players[msg.sender].totalScore += score;
players[msg.sender].lastPlayed = 0; // Reset status permainan
// Panggil fungsi scalable untuk memperbarui leaderboard
_updateTop10(msg.sender, players[msg.sender].totalScore);
emit ScoreSubmitted(msg.sender, score);
}
// --- FUNGSI ADMIN UNTUK FLEKSIBILITAS ---
function setStartFee(uint256 newFee) external onlyOwner {
startFeeWei = newFee;
emit FeeUpdated(newFee);
}
function setMaxScore(uint256 newMaxScore) external onlyOwner {
maxScorePerSubmit = newMaxScore;
emit MaxScoreUpdated(newMaxScore);
}
function transferOwnership(address newOwner) external onlyOwner {
require(newOwner != address(0), "New owner is zero address");
address previousOwner = owner;
owner = newOwner;
emit OwnershipTransferred(previousOwner, newOwner);
}
// --- FUNGSI RETRIEVAL (EFEK GAS) ---
function getTop10()
external
view
returns (address[] memory topPlayers, uint256[] memory scores)
{
uint256 count = 0;
for (uint256 i = 0; i < 10; i++) {
if (top10Wallets[i] != address(0) && top10Scores[i] > 0) {
count++;
}
}
topPlayers = new address[](count);
scores = new uint256[](count);
for (uint256 i = 0; i < count; i++) {
topPlayers[i] = top10Wallets[i];
scores[i] = top10Scores[i];
}
}
function withdraw() external onlyOwner {
uint256 bal = address(this).balance;
require(bal > 0, "Empty");
payable(treasury).transfer(bal); // Menggunakan variabel treasury
emit Withdraw(treasury, bal);
}
}
ABI · 21 entries
json
[
{
"type": "constructor",
"inputs": [
{
"name": "_treasury",
"type": "address",
"internalType": "address"
},
{
"name": "_startFeeWei",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "_maxScorePerSubmit",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "nonpayable"
},
{
"name": "FeeUpdated",
"type": "event",
"inputs": [
{
"name": "newFee",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
}
],
"anonymous": false
},
{
"name": "GameStarted",
"type": "event",
"inputs": [
{
"name": "player",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "fee",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
}
],
"anonymous": false
},
{
"name": "MaxScoreUpdated",
"type": "event",
"inputs": [
{
"name": "newMaxScore",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
}
],
"anonymous": false
},
{
"name": "OwnershipTransferred",
"type": "event",
"inputs": [
{
"name": "previousOwner",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "newOwner",
"type": "address",
"indexed": true,
"internalType": "address"
}
],
"anonymous": false
},
{
"name": "ScoreSubmitted",
"type": "event",
"inputs": [
{
"name": "player",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "score",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
}
],
"anonymous": false
},
{
"name": "Withdraw",
"type": "event",
"inputs": [
{
"name": "to",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "amount",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
}
],
"anonymous": false
},
{
"name": "getTop10",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "topPlayers",
"type": "address[]",
"internalType": "address[]"
},
{
"name": "scores",
"type": "uint256[]",
"internalType": "uint256[]"
}
],
"stateMutability": "view"
},
{
"name": "maxScorePerSubmit",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "owner",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"name": "players",
"type": "function",
"inputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "totalScore",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "lastPlayed",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "setMaxScore",
"type": "function",
"inputs": [
{
"name": "newMaxScore",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "setStartFee",
"type": "function",
"inputs": [
{
"name": "newFee",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "startFeeWei",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "startGame",
"type": "function",
"inputs": [],
"outputs": [],
"stateMutability": "payable"
},
{
"name": "submitScore",
"type": "function",
"inputs": [
{
"name": "score",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "top10Scores",
"type": "function",
"inputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "top10Wallets",
"type": "function",
"inputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"name": "transferOwnership",
"type": "function",
"inputs": [
{
"name": "newOwner",
"type": "address",
"internalType": "address"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "treasury",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"name": "withdraw",
"type": "function",
"inputs": [],
"outputs": [],
"stateMutability": "nonpayable"
}
]