Created
July 29, 2024 07:50
-
-
Save levancho/86b3b02276a15595e3de46d95d0614cf to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.8.26+commit.8a97fa7a.js&optimize=false&runs=200&gist=
This file contains hidden or 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
// SPDX-License-Identifier: GPL-3.0 | |
pragma solidity >=0.8.2 <0.9.0; | |
import "hardhat/console.sol"; | |
contract LuckyChainSimple { | |
address public manager; | |
uint public level = 1; | |
uint public totalSeats = 0; | |
uint public lotteryPoolInWei = 0; | |
uint public lotteryContributionPercentage; | |
uint public entryPriceInWei; | |
struct Seat { | |
address owner; | |
uint seatNumber; | |
uint level; | |
uint localSeatNumber; // Local seat number within the level | |
} | |
// Mapping from level to array of seats | |
mapping(uint => Seat[]) public levelSeats; | |
// Keep track of seat numbers for the lottery | |
uint[] public seatNumbers; | |
event SeatPurchasedEvent(address indexed buyer, uint level, uint seatNumber, uint localSeatNumber); | |
event LotteryWinnersEvent(address[] winners, uint amountPerWinnerInWei); | |
event DistributionEvent(address indexed recipient, uint amountInWei, uint level, string distributionType); | |
event SeatAddedToLotteryEvent(uint seatNumber, uint level); | |
event LevelChangedEvent(uint oldLevel, uint newLevel); | |
event LotteryContributionEvent(uint contributionInWei); | |
event RemainingRevenueEvent(uint remainingRevenueInWei); | |
event LotteryContributionPercentageChangedEvent(uint oldPercentage, uint newPercentage); | |
constructor(uint _entryPriceInWei, uint _lotteryContributionPercentage) { | |
manager = msg.sender; | |
entryPriceInWei = _entryPriceInWei; | |
setLotteryContributionPercentage(_lotteryContributionPercentage); | |
console.log("Contract deployed by:", manager); | |
console.log("Entry price in Wei:", entryPriceInWei); | |
console.log("Lottery contribution percentage:", lotteryContributionPercentage); | |
} | |
// Modifier to check if the caller is the manager | |
modifier onlyManager() { | |
require(msg.sender == manager, "Caller is not the manager"); | |
_; | |
} | |
function setLotteryContributionPercentage(uint newPercentage) private { | |
require(newPercentage >= 0 && newPercentage <= 100, "Percentage must be between 0 and 100"); | |
uint oldPercentage = lotteryContributionPercentage; | |
lotteryContributionPercentage = newPercentage == 0 ? 20 : newPercentage; | |
emit LotteryContributionPercentageChangedEvent(oldPercentage, lotteryContributionPercentage); | |
console.log("Lottery contribution percentage changed from %s to %s", oldPercentage, lotteryContributionPercentage); | |
} | |
function buySeat() public payable { | |
console.log("Entering buySeat()"); | |
require(msg.value == entryPriceInWei, "Incorrect seat price"); | |
console.log("Buying seat with price:", msg.value); | |
console.log("by:", msg.sender); | |
// Check if the current level is full | |
uint oldLevel = level; | |
if (levelSeats[level].length == getSeatsForLevel(level)) { | |
level++; // Move to the next level if current level is full | |
console.log("Moving to next level:", level); | |
emit LevelChangedEvent(oldLevel, level); | |
} | |
uint seatNumber = totalSeats + 1; | |
uint localSeatNumber = levelSeats[level].length + 1; | |
totalSeats++; | |
// Add the seat to the levelSeats mapping | |
levelSeats[level].push(Seat(msg.sender, seatNumber, level, localSeatNumber)); | |
console.log("Seat added: global seatNumber:", seatNumber); | |
console.log("localSeatNumber:", localSeatNumber); | |
console.log("level:", level); | |
addSeatToLottery(seatNumber, level); | |
// Revenue distribution | |
uint rowRevenueInWei = msg.value; | |
uint lotteryContributionInWei = (rowRevenueInWei * lotteryContributionPercentage) / 100; | |
lotteryPoolInWei += lotteryContributionInWei; | |
emit LotteryContributionEvent(lotteryContributionInWei); | |
console.log("Lottery contribution:", lotteryContributionInWei); | |
uint remainingRevenueInWei = rowRevenueInWei - lotteryContributionInWei; | |
emit RemainingRevenueEvent(remainingRevenueInWei); | |
console.log("Remaining revenue:", remainingRevenueInWei); | |
uint bottomUpAmountInWei = remainingRevenueInWei / 2; | |
uint topDownAmountInWei = remainingRevenueInWei - bottomUpAmountInWei; | |
console.log("Bottom-up amount:", bottomUpAmountInWei); | |
console.log("Top-down amount:", topDownAmountInWei); | |
distributeBottomUp(bottomUpAmountInWei, level); | |
distributeTopDown(topDownAmountInWei, level); | |
emit SeatPurchasedEvent(msg.sender, level, seatNumber, localSeatNumber); | |
console.log("Seat purchased: level %s, seatNumber %s, localSeatNumber %s", level, seatNumber, localSeatNumber); | |
console.log("Exiting buySeat()"); | |
} | |
function distributeBottomUp(uint amountInWei, uint currentLevel) private { | |
console.log("Entering distributeBottomUp()"); | |
console.log("Distributing bottom up from level:", currentLevel - 1); | |
console.log("amount:", amountInWei); | |
for (uint lvl = currentLevel - 1; lvl > 0 && amountInWei > 0; lvl--) { | |
uint seatsAtLevel = levelSeats[lvl].length; | |
console.log("Level:", lvl); | |
console.log("Seats at level:", seatsAtLevel); | |
console.log("Current amount:", amountInWei); | |
if (seatsAtLevel > 0) { | |
uint amountPerSeatInWei = amountInWei / 2 / seatsAtLevel; | |
for (uint i = 0; i < seatsAtLevel; i++) { | |
payable(levelSeats[lvl][i].owner).transfer(amountPerSeatInWei); | |
emit DistributionEvent(levelSeats[lvl][i].owner, amountPerSeatInWei, lvl, "BottomUp"); | |
console.log("Distributed %s to %s at level %s", amountPerSeatInWei, levelSeats[lvl][i].owner, lvl); | |
} | |
amountInWei /= 2; | |
} | |
} | |
console.log("Exiting distributeBottomUp()"); | |
} | |
function distributeTopDown(uint amountInWei, uint currentLevel) private { | |
console.log("Entering distributeTopDown()"); | |
console.log("Distributing top down to level:", currentLevel); | |
console.log("amount:", amountInWei); | |
for (uint lvl = 1; lvl <= currentLevel && amountInWei > 0; lvl++) { | |
uint seatsAtLevel = levelSeats[lvl].length; | |
console.log("Level:", lvl); | |
console.log("Seats at level:", seatsAtLevel); | |
console.log("Current amount:", amountInWei); | |
if (seatsAtLevel > 0) { | |
uint amountPerSeatInWei = amountInWei / 2 / seatsAtLevel; | |
for (uint i = 0; i < seatsAtLevel; i++) { | |
payable(levelSeats[lvl][i].owner).transfer(amountPerSeatInWei); | |
emit DistributionEvent(levelSeats[lvl][i].owner, amountPerSeatInWei, lvl, "TopDown"); | |
console.log("Distributed %s to %s at level %s", amountPerSeatInWei, levelSeats[lvl][i].owner, lvl); | |
} | |
amountInWei /= 2; | |
} | |
} | |
console.log("Exiting distributeTopDown()"); | |
} | |
function addSeatToLottery(uint seatNumber, uint level) private { | |
console.log("Entering addSeatToLottery()"); | |
for (uint i = 0; i < level; i++) { | |
seatNumbers.push(seatNumber); | |
} | |
console.log("Added seat number %s to lottery %s times", seatNumber, level); | |
emit SeatAddedToLotteryEvent(seatNumber, level); | |
console.log("Exiting addSeatToLottery()"); | |
} | |
function drawLottery() public onlyManager { | |
console.log("Entering drawLottery()"); | |
require(seatNumbers.length > 0, "No seats in the lottery"); | |
console.log("Drawing lottery"); | |
uint numWinners = totalSeats / level; | |
address[] memory winners = new address[](numWinners); | |
uint prizePerWinnerInWei = lotteryPoolInWei / numWinners; | |
for (uint i = 0; i < numWinners; i++) { | |
uint winnerIndex = random() % seatNumbers.length; | |
uint winningSeat = seatNumbers[winnerIndex]; | |
winners[i] = getSeatOwner(winningSeat); | |
payable(winners[i]).transfer(prizePerWinnerInWei); | |
// Remove the winning seat number from the pool | |
seatNumbers[winnerIndex] = seatNumbers[seatNumbers.length - 1]; | |
seatNumbers.pop(); | |
console.log("Winner: %s, Prize: %s", winners[i], prizePerWinnerInWei); | |
} | |
lotteryPoolInWei = 0; | |
emit LotteryWinnersEvent(winners, prizePerWinnerInWei); | |
console.log("Exiting drawLottery()"); | |
} | |
function random() private view returns (uint) { | |
console.log("Entering random()"); | |
uint result = uint(keccak256(abi.encodePacked(block.difficulty, block.timestamp, seatNumbers))); | |
console.log("Exiting random() with result:", result); | |
return result; | |
} | |
function getSeatOwner(uint seatNumber) private view returns (address) { | |
console.log("Entering getSeatOwner() with seatNumber:", seatNumber); | |
for (uint lvl = 1; lvl <= level; lvl++) { | |
Seat[] storage seats = levelSeats[lvl]; | |
for (uint i = 0; i < seats.length; i++) { | |
if (seats[i].seatNumber == seatNumber) { | |
console.log("Exiting getSeatOwner() with owner:", seats[i].owner); | |
return seats[i].owner; | |
} | |
} | |
} | |
revert("Seat owner not found"); | |
} | |
function getSeatsByLevel(uint lvl) public view returns (Seat[] memory) { | |
console.log("Entering getSeatsByLevel() with level:", lvl); | |
Seat[] memory result = levelSeats[lvl]; | |
console.log("Exiting getSeatsByLevel() with result:"); | |
for (uint i = 0; i < result.length; i++) { | |
console.log("Seat owner:", result[i].owner); | |
console.log("Seat number:", result[i].seatNumber); | |
console.log("Seat level:", result[i].level); | |
console.log("Local seat number:", result[i].localSeatNumber); | |
} | |
return result; | |
} | |
function getAllSeats() public view returns (Seat[] memory) { | |
console.log("Entering getAllSeats()"); | |
Seat[] memory allSeats = new Seat[](totalSeats); | |
uint index = 0; | |
for (uint lvl = 1; lvl <= level; lvl++) { | |
Seat[] storage seats = levelSeats[lvl]; | |
for (uint i = 0; i < seats.length; i++) { | |
allSeats[index] = seats[i]; | |
index++; | |
} | |
} | |
console.log("Exiting getAllSeats() with result:"); | |
for (uint i = 0; i < allSeats.length; i++) { | |
console.log("Seat owner:", allSeats[i].owner); | |
console.log("Seat number:", allSeats[i].seatNumber); | |
console.log("Seat level:", allSeats[i].level); | |
console.log("Local seat number:", allSeats[i].localSeatNumber); | |
} | |
return allSeats; | |
} | |
function getSeatsForLevel(uint lvl) public pure returns (uint) { | |
console.log("Entering getSeatsForLevel() with level:", lvl); | |
require(lvl > 0, "Level must be greater than 0"); | |
uint result = 2 ** (lvl - 1); | |
console.log("Exiting getSeatsForLevel() with result:", result); | |
return result; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment