Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
257 lines (230 sloc) 10.6 KB
pragma solidity ^0.4.20;
/// @title Store lederboards in the Blockchain
/// @author Marcel Scherello blockscores@scherello.de
/// @notice Create a custom leaderboard and start counting the scores
/// @dev All function calls are currently implement without side effects
/// @dev v1.1.0
contract BlockScores {
struct Player {
bytes32 playerName;
address playerAddress;
uint score;
uint score_unconfirmed;
uint isActive;
}
struct Board {
bytes32 boardName;
string boardDescription;
uint numPlayers;
address boardOwner;
mapping (uint => Player) players;
}
mapping (bytes32 => Board) boards;
uint public numBoards;
address owner = msg.sender;
uint public balance;
uint public boardCost = 1000000000000000;
uint public playerCost = 1000000000000000;
modifier isOwner {
assert(owner == msg.sender);
_;
}
/**
Funding Functions
*/
/// @notice withdraw all funds to contract owner
/// @return true
function withdraw() isOwner public returns(bool) {
uint _amount = address(this).balance;
emit Withdrawal(owner, _amount);
owner.transfer(_amount);
balance -= _amount;
return true;
}
/// @notice change the costs for using the contract
/// @param costBoard costs for a new board
/// @param costPlayer costs for a new player
/// @return true
function setCosts (uint costBoard, uint costPlayer) isOwner public returns(bool) {
boardCost = costBoard;
playerCost = costPlayer;
return true;
}
/// @notice split the revenue of a new player between boardOwner and contract owner
/// @param boardOwner of the leaderboard
/// @param _amount amount to be split
/// @return true
function split(address boardOwner, uint _amount) internal returns(bool) {
emit Withdrawal(owner, _amount/2);
owner.transfer(_amount/2);
//emit Withdrawal(boardOwner, _amount/2);
boardOwner.transfer(_amount/2);
return true;
}
/// @notice Event for Withdrawal
event Withdrawal(address indexed _from, uint _value);
/**
Board Functions
*/
/// @notice Add a new leaderboard. Board hash will be created by name and creator
/// @notice a funding is required to create a new leaderboard
/// @param name The name of the leaderboard
/// @param boardDescription A subtitle for the leaderboard
/// @return The hash of the newly created leaderboard
function addNewBoard(bytes32 name, string boardDescription) public payable returns(bytes32 boardHash){
require(msg.value >= boardCost);
balance += msg.value;
boardHash = keccak256(abi.encodePacked(name, msg.sender));
numBoards++;
boards[boardHash] = Board(name, boardDescription, 0, msg.sender);
emit newBoardCreated(boardHash);
}
/// @notice Simulate the creation of a leaderboard hash
/// @param name The name of the leaderboard
/// @param admin The address of the admin address
/// @return The possible hash of the leaderboard
function createBoardHash(bytes32 name, address admin) pure public returns (bytes32){
return keccak256(abi.encodePacked(name, admin));
}
/// @notice Get the metadata of a leaderboard
/// @param boardHash The hash of the leaderboard
/// @return Leaderboard name, description and number of players
function getBoardByHash(bytes32 boardHash) constant public returns(bytes32,string,uint){
return (boards[boardHash].boardName, boards[boardHash].boardDescription, boards[boardHash].numPlayers);
}
/// @notice Overwrite leaderboard name and desctiption as owner only
/// @param boardHash The hash of the leaderboard to be modified
/// @param name The new name of the leaderboard
/// @param boardDescription The new subtitle for the leaderboard
/// @return true
function changeBoardMetadata(bytes32 boardHash, bytes32 name, string boardDescription) public returns(bool) {
require(boards[boardHash].boardOwner == msg.sender);
boards[boardHash].boardName = name;
boards[boardHash].boardDescription = boardDescription;
}
/// @notice event for newly created leaderboard
event newBoardCreated(bytes32 boardHash);
/**
Player Functions
*/
/// @notice Add a new player to an existing leaderboard
/// @param boardHash The hash of the leaderboard
/// @param playerName The name of the player
/// @return Player ID
function addPlayerToBoard(bytes32 boardHash, bytes32 playerName) public payable returns (bool) {
require(msg.value >= playerCost);
Board storage g = boards[boardHash];
split (g.boardOwner, msg.value);
uint newPlayerID = g.numPlayers++;
g.players[newPlayerID] = Player(playerName, msg.sender,0,0,1);
return true;
}
/// @notice Get player data by leaderboard hash and player id/index
/// @param boardHash The hash of the leaderboard
/// @param playerID Index number of the player
/// @return Player name, confirmed score, unconfirmed score
function getPlayerByBoard(bytes32 boardHash, uint8 playerID) constant public returns (bytes32, uint, uint){
Player storage p = boards[boardHash].players[playerID];
require(p.isActive == 1);
return (p.playerName, p.score, p.score_unconfirmed);
}
/// @notice The leaderboard owner can remove a player
/// @param boardHash The hash of the leaderboard
/// @param playerName The name of the player to be removed
/// @return true/false
function removePlayerFromBoard(bytes32 boardHash, bytes32 playerName) public returns (bool){
Board storage g = boards[boardHash];
require(g.boardOwner == msg.sender);
uint8 playerID = getPlayerId (boardHash, playerName, 0);
require(playerID < 255 );
g.players[playerID].isActive = 0;
return true;
}
/// @notice Get the player id either by player Name or address
/// @param boardHash The hash of the leaderboard
/// @param playerName The name of the player
/// @param playerAddress The player address
/// @return ID or 999 in case of false
function getPlayerId (bytes32 boardHash, bytes32 playerName, address playerAddress) constant internal returns (uint8) {
Board storage g = boards[boardHash];
for (uint8 i = 0; i <= g.numPlayers; i++) {
if ((keccak256(abi.encodePacked(g.players[i].playerName)) == keccak256(abi.encodePacked(playerName)) || playerAddress == g.players[i].playerAddress) && g.players[i].isActive == 1) {
return i;
break;
}
}
return 255;
}
/**
Score Functions
*/
/// @notice Add a unconfirmed score to leaderboard/player. Overwrites an existing unconfirmed score
/// @param boardHash The hash of the leaderboard
/// @param playerName The name of the player
/// @param score Integer
/// @return true/false
function addBoardScore(bytes32 boardHash, bytes32 playerName, uint score) public returns (bool){
uint8 playerID = getPlayerId (boardHash, playerName, 0);
require(playerID < 255 );
boards[boardHash].players[playerID].score_unconfirmed = score;
return true;
}
/// @notice Confirm an unconfirmed score to leaderboard/player. Adds unconfirmed to existing score. Player can not confirm his own score
/// @param boardHash The hash of the leaderboard
/// @param playerName The name of the player who's score should be confirmed
/// @return true/false
function confirmBoardScore(bytes32 boardHash, bytes32 playerName) public returns (bool){
uint8 playerID = getPlayerId (boardHash, playerName, 0);
uint8 confirmerID = getPlayerId (boardHash, "", msg.sender);
require(playerID < 255); // player needs to be active
require(confirmerID < 255); // confirmer needs to be active
require(boards[boardHash].players[playerID].playerAddress != msg.sender); //confirm only other players
boards[boardHash].players[playerID].score += boards[boardHash].players[playerID].score_unconfirmed;
boards[boardHash].players[playerID].score_unconfirmed = 0;
return true;
}
/**
Migration Functions
*/
/// @notice Read board metadata for migration as contract owner only
/// @param boardHash The hash of the leaderboard
/// @return Bord metadata
function migrationGetBoard(bytes32 boardHash) constant isOwner public returns(bytes32,string,uint,address) {
return (boards[boardHash].boardName, boards[boardHash].boardDescription, boards[boardHash].numPlayers, boards[boardHash].boardOwner);
}
/// @notice Write board metadata for migration as contract owner only
/// @param boardHash The hash of the leaderboard to be modified
/// @param name The new name of the leaderboard
/// @param boardDescription The new subtitle for the leaderboard
/// @param boardOwner The address for the boardowner
/// @return true
function migrationSetBoard(bytes32 boardHash, bytes32 name, string boardDescription, uint8 numPlayers, address boardOwner) isOwner public returns(bool) {
boards[boardHash].boardName = name;
boards[boardHash].boardDescription = boardDescription;
boards[boardHash].numPlayers = numPlayers;
boards[boardHash].boardOwner = boardOwner;
return true;
}
/// @notice Read player metadata for migration as contract owner
/// @param boardHash The hash of the leaderboard
/// @param playerID Index number of the player
/// @return Player metadata
function migrationGetPlayer(bytes32 boardHash, uint8 playerID) constant isOwner public returns (uint, bytes32, address, uint, uint, uint){
Player storage p = boards[boardHash].players[playerID];
return (playerID, p.playerName, p.playerAddress, p.score, p.score_unconfirmed, p.isActive);
}
/// @notice Write player metadata for migration as contract owner only
/// @param boardHash The hash of the leaderboard
/// @param playerID Player ID
/// @param playerName Player name
/// @param playerAddress Player address
/// @param score Player score
/// @param score_unconfirmed Player unconfirmed score
/// @param isActive Player isActive
/// @return true
function migrationSetPlayer(bytes32 boardHash, uint playerID, bytes32 playerName, address playerAddress, uint score, uint score_unconfirmed, uint isActive) isOwner public returns (bool) {
Board storage g = boards[boardHash];
g.players[playerID] = Player(playerName, playerAddress, score, score_unconfirmed, isActive);
return true;
}
}