This repository has been archived by the owner on Nov 7, 2023. It is now read-only.
/
BlockScores.sol
257 lines (230 loc) · 10.6 KB
/
BlockScores.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
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;
}
}