Skip to content

Instantly share code, notes, and snippets.

@kbahr
Created February 21, 2020 21:54
Show Gist options
  • Save kbahr/08e3a303bba1034eb2cfc2633fbc735f to your computer and use it in GitHub Desktop.
Save kbahr/08e3a303bba1034eb2cfc2633fbc735f to your computer and use it in GitHub Desktop.
Proposed solution to the lotto entry traversal issue
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