Created
February 21, 2020 21:54
-
-
Save kbahr/08e3a303bba1034eb2cfc2633fbc735f to your computer and use it in GitHub Desktop.
Proposed solution to the lotto entry traversal issue
This file contains 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
pragma solidity >=0.5.16 | |
contract HEXLotto { | |
// I didn't see where hexAmount was ever used | |
struct Entry { | |
uint256 ticketNumber; // could be uint96 to save space (12bytes + 20bytes address) | |
address buyer; | |
} | |
uint256 public hourlyTickets; | |
uint256 public dailyTickets; | |
uint256 public weeklyTickets; | |
uint256 public monthlyTickets; | |
uint256 public yearlyTickets; | |
uint256 public threeYearlyTickets; | |
Entry[] public hourlyParticipants; | |
Entry[] public dailyParticipants; | |
Entry[] public weeklyParticipants; | |
Entry[] public monthlyParticipants; | |
Entry[] public yearlyParticipants; | |
Entry[] public threeYearlyParticipants; | |
/** | |
* @dev Creates ticket entries into arrays for all tiers | |
*/ | |
function saveEntries(uint256 tickets, uint256[9] memory quantities ) private { | |
Entry memory hourlyEntry = Entry(msg.sender, hourlyTickets + tickets); | |
Entry memory dailyEntry = Entry(msg.sender, dailyTickets + tickets); | |
Entry memory weeklyEntry = Entry(msg.sender, weeklyTickets + tickets); | |
Entry memory monthlyEntry = Entry(msg.sender, monthlyTickets + tickets); | |
Entry memory yearlyEntry = Entry(msg.sender, yearlyTickets + tickets); | |
Entry memory threeYearlyEntry = Entry(msg.sender, threeYearlyTickets + tickets); | |
hourlyParticipants.push(hourlyEntry); | |
dailyParticipants.push(dailyEntry); | |
weeklyParticipants.push(weeklyEntry); | |
monthlyParticipants.push(monthlyEntry); | |
yearlyParticipants.push(yearlyEntry); | |
threeYearlyParticipants.push(threeYearlyEntry); | |
hourlyTickets += tickets; | |
dailyTickets += tickets; | |
weeklyTickets += tickets; | |
monthlyTickets += tickets; | |
yearlyTickets += tickets; | |
threeYearlyTickets += tickets; | |
players.push(msg.sender); | |
} | |
/** | |
* @dev Distributes HEX quantities into the relevant tiers, treasury wallets and approves for HEX2 | |
*/ | |
function distribute(uint256 quantity) private returns(uint256[9] memory) { | |
uint256[9] memory quantities; | |
quantities[0] = quantity.mul(34).div(100); //Hourly | |
quantities[1] = quantity.mul(23).div(100); //Daily | |
quantities[2] = quantity.mul(18).div(100); //Weekly | |
quantities[3] = quantity.mul(10).div(100); //Monthly | |
quantities[4] = quantity.mul(4).div(100); //300 days | |
quantities[5] = quantity.mul(1).div(100); //3 yearly | |
quantities[6] = quantity.mul(6).div(100); //Treasury | |
quantities[7] = quantity.mul(1).div(100); //Hex2 | |
quantities[8] = quantity.mul(3).div(100); //Dev wallet | |
//send 6% to treasury | |
require(ERC20(token).transfer(owner(), quantities[6])); | |
//approve 1% for hex2 distribution | |
//need to call hex distribute function after tokens are approved | |
ERC20(token).approve(hex2, quantities[7]); | |
hex2amount += quantities[7]; | |
//send 3% to dev | |
require(ERC20(token).transfer(devWallet, quantities[8])); | |
hourlyPot += quantities[0]; | |
dailyPot += quantities[1]; | |
weeklyPot += quantities[2]; | |
monthlyPot += quantities[3]; | |
yearlyPot += quantities[4]; | |
threeYearlyPot += quantities[5]; | |
return quantities; | |
} | |
/** | |
* @dev Returns a winner address chosen at random from the participant list | |
*/ | |
function pickWinner(Entry[] memory entries, uint256 random) internal returns(address) { | |
address winner; | |
uint256 l = 0; | |
uint256 r = entries.length-1; | |
uint256 m; | |
while(l <= r){ | |
m = (l+r) >> 1; // floor((left + right) / 2) | |
// bad - we're at the first index which is a "sentinel" | |
if(m == 0){ | |
require(false, "Sentinel value, no valid winner"); | |
} | |
uint256 t = entries[m].ticketNumber; | |
if (t < random) { | |
// too small, check top half | |
l = m + 1; | |
} else { | |
// t >= counter | |
if(entries[m-1].ticketNumber >= random) { | |
// this ticket number is "much greater" than the target, meaning its predecessor | |
// is also greater | |
r = m - 1; | |
} else { | |
// winner! the random number is between the ticket number of the prior entry and | |
// equal to or less than this ticket number (in the range t0 - t1) | |
winner = entries[m].buyer; | |
break; | |
} | |
} | |
} | |
emit generatedRandomNumber(random); | |
return winner; | |
} | |
/** | |
* @dev Transfers prize to random winner | |
*/ | |
function pickWeeklyWinner(uint256 random, uint256 prizeAmount) private { | |
uint256 randomWinner = random % weeklyTickets - 1; | |
address weeklyWinner = pickWinner(weeklyParticipants, randomWinner); | |
require(weeklyWinner != address(0), "Can not send to 0 address"); | |
require(ERC20(token).transfer(weeklyWinner, prizeAmount), "Transfer failed"); | |
playerStats[weeklyWinner].amountWon += prizeAmount; | |
weeklyPot -= prizeAmount; | |
if(weeklyPot < 2){ | |
lastWeekly = now; | |
weeklyTickets = 0; | |
delete weeklyParticipants; | |
// reset with a sentinel value for the "0" ticket number | |
weeklyParticipants.push(Entry(weeklyTickets, address(0))); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment