Skip to content

Instantly share code, notes, and snippets.

@uneeb123
Last active July 19, 2024 21:49
Show Gist options
  • Save uneeb123/4ab6d7dc0df2b7f207646c69155571ef to your computer and use it in GitHub Desktop.
Save uneeb123/4ab6d7dc0df2b7f207646c69155571ef to your computer and use it in GitHub Desktop.
New Blast Lottery contract and adjusting existing Lottery contract
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.23;
import {IEntropyConsumer} from "@pythnetwork/entropy-sdk-solidity/IEntropyConsumer.sol";
import {IEntropy} from "@pythnetwork/entropy-sdk-solidity/IEntropy.sol";
import "blast-l2-kit/src/IBlast.sol";
import "blast-l2-kit/src/IBlastPoints.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
contract BlastLottery is
Initializable,
Ownable2StepUpgradeable,
UUPSUpgradeable,
IEntropyConsumer
{
// Randomness variables
IEntropy private entropy;
address private entropyProvider;
// Blast variables
address public blastGasYieldContract;
address public blastPointsContract;
address private governor; // Store the governor address
address private pointsOperator; // Store the points operator address
struct User {
// Total tickets purchased by the user for current lottery, multiplied by 10000, resets each lottery
uint256 ticketsPurchasedTotalBps;
// Tracks the total win amount in ETH (how much the user can withdraw)
uint256 winningsClaimable;
// Whether or not the user is participating in the current lottery
bool active;
}
struct LP {
uint256 principal;
uint256 stake;
uint256 riskPercentage; // From 0 to 100
// Whether or not the LP has principal stored in the contract
bool active;
}
mapping(address => User) public usersInfo;
mapping(address => LP) public lpsInfo;
// array to keep track of active user addresses for current lottery, resets on each lottery run
// user addresses are added when they purchase tickets
// user addresses are removed when the lottery is run
address[] private activeUserAddresses;
// array to keep track of active LP addresses, does not reset on lottery run
// lp addresses are added when they become active (by depositing)
// lp addresses are removed when they become inactive (by withdrawing)
address[] public activeLpAddresses;
// LOTTERY VARIABLES
// ticket price
uint256 public ticketPrice;
// round duration in seconds
uint256 public roundDurationInSeconds;
// timestamp of the last lottery end time
uint256 public lastLotteryEndTime;
// total amount in LP pool
uint256 public lpPoolTotal;
// cap for LP pool/stake (not total LP assets or deposits)
uint256 public lpPoolCap;
// total amount in user pool in ETH
uint256 public userPoolTotal;
// total tickets purchased by players, post-fee, multiplied by 10000, does not include LP tickets
uint256 public ticketCountTotalBps;
// most recent winner's address
address public lastWinnerAddress;
// set to true when run lottery is initiated, if true, lottery cannot be run twice
bool public lotteryLock;
// set to true when entropy callback has been run, if true, entropy callback cannot be run twice
bool public entropyCallbackLock;
// LP FEE AND REFERRAL FEE SETTINGS AND VARIABLES
uint256 public feeBps;
// total fee amount for both LP's and referrals
uint256 public allFeesTotal;
// total amount given to LP's via fees
uint256 public lpFeesTotal;
// fee Bps for referrals
uint256 public referralFeeBps;
// total referral fees allocated across all referrers
uint256 public referralFeesTotal;
// how much each referrer has received in referral fees
mapping(address => uint256) public referralFeesClaimable;
// Protocol fee address, see conditions below when this applies
address public protocolFeeAddress;
// Amount of protocol fees claimable
uint256 public protocolFeeClaimable;
// Fallback address in case winner is not found
address public fallbackWinner;
// Limit for number of active LPs
uint256 public lpLimit;
// Minimum amount LPs can deposit
uint256 public minLpDeposit;
// Limit for number of active users
uint256 public userLimit;
// Pause ticket purchasing
bool public allowPurchasing;
// Blast token to use
IERC20 public blastToken;
// Threshold after which protocol starts taking fees
uint256 public protocolFeeThreshold;
// EVENTS
event UserTicketPurchase(
address indexed user,
uint256 ticketsPurchasedTotalBps
);
event UserWinWithdrawal(address indexed user, uint256 amount);
event UserReferralFeeWithdrawal(address indexed user, uint256 amount);
event ProtocolFeeWithdrawal(uint256 amount);
event LpDeposit(
address indexed lpAddress,
uint256 amount,
uint256 riskPercentage
);
event LpPrincipalWithdrawal(
address indexed lpAddress,
uint256 principalAmount
);
event LotteryRunRequested(address indexed user);
event LotteryRun(
uint256 time,
address winner,
uint256 winningTicket,
uint256 winAmount,
uint256 ticketsPurchasedTotalBps
);
event EntropyResult(uint64 sequenceNumber, bytes32 randomNumber);
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
function _authorizeUpgrade(
address newImplementation
) internal override onlyOwner {}
function initialize(
address _entropy,
address _blastGasYieldContract,
address _blastPointsContract,
address _blastPointsOperator,
address _blastGovernor,
uint256 _feeBps,
uint256 _referralFeeBps,
uint256 _lpPoolCap,
address _blastToken
) public initializer {
__Ownable_init(msg.sender);
__UUPSUpgradeable_init();
require(_feeBps <= 2000, "Fee bps should not exceed 2000");
require(
_referralFeeBps <= _feeBps,
"Referral bps should not exceed fee bps"
);
feeBps = _feeBps;
referralFeeBps = _referralFeeBps;
entropy = IEntropy(_entropy); // Address of Entropy contract
entropyProvider = entropy.getDefaultProvider();
lastLotteryEndTime = block.timestamp;
lpPoolCap = _lpPoolCap; // Set initial LP pool cap
roundDurationInSeconds = 86400;
blastGasYieldContract = _blastGasYieldContract;
blastPointsContract = _blastPointsContract;
fallbackWinner = msg.sender;
lpLimit = 100;
userLimit = 1500;
allowPurchasing = false;
// Configure the contract for automatic yield and claimable gas on Blast
IBlast(blastGasYieldContract).configureClaimableYield();
IBlast(blastGasYieldContract).configureClaimableGas();
IBlast(blastGasYieldContract).configureGovernor(_blastGovernor);
// configure Points Operator
IBlastPoints(blastPointsContract).configurePointsOperator(
_blastPointsOperator
);
blastToken = IERC20(_blastToken);
ticketPrice = 100 * (10 ** 18);
minLpDeposit = 10_000 * (10 ** 18);
protocolFeeThreshold = 100_000 * (10 ** 18);
}
/********************
* *
* ENTROPY *
* *
********************/
// It returns the address of the entropy contract which will call the callback.
function getEntropy() internal view override returns (address) {
return address(entropy);
}
// It is called by the entropy contract when a random number is generated.
function entropyCallback(
uint64 sequenceNumber,
address,
bytes32 randomNumber
) internal override {
emit EntropyResult(sequenceNumber, randomNumber);
require(!entropyCallbackLock, "Entropy callback lock already set");
require(lotteryLock, "Lottery lock needs to be set");
entropyCallbackLock = true;
determineWinnerAndAdjustStakes(randomNumber);
// release both locks
lotteryLock = false;
entropyCallbackLock = false;
}
/********************
* *
* BLAST *
* *
********************/
function setBlastGasYieldAddress(address _addr) external onlyOwner {
blastGasYieldContract = _addr;
}
function setBlastPointsAddress(address _addr) external onlyOwner {
blastPointsContract = _addr;
}
function configureBlastPointsOperator(
address _operator
) external onlyOwner {
IBlastPoints(blastPointsContract).configurePointsOperator(_operator);
}
/*
Claim a specific amount of yield.
*/
function claimYield(
address _recipient,
uint256 _amount
) external onlyOwner {
IBlast(blastGasYieldContract).claimYield(
address(this),
_recipient,
_amount
);
}
/*
Claim all yield on the contract
*/
function claimAllYield(address _recipient) external onlyOwner {
IBlast(blastGasYieldContract).claimAllYield(address(this), _recipient);
}
/*
If you’d like to maximize the amount of gas fees, then you can use
claimMaxGas to guarantee a 100% claim rate. Only gas fees that have
fully matured (30 days) will be claimed. Any remaining fees after
calling this function will remain in the Blast Gas contract for you
to claim later.
*/
function claimMaxGas(address _recipient) external onlyOwner {
IBlast(blastGasYieldContract).claimMaxGas(address(this), _recipient);
}
/*
To claim all of your contract’s gas fees, regardless of
your resulting claim rate, you can call claimAllGas. Your
resulting claim rate may be anywhere from 50% to 100% depending
on how long it has been since the fees were earned.
*/
function claimAllGas(address _recipient) external onlyOwner {
IBlast(blastGasYieldContract).claimAllGas(address(this), _recipient);
}
/*
Allows you to claim the maximum amount of gas fees while
guaranteeing a specific claim rate. If you’re comfortable with
an 80% claim rate, that translates to 8000 bip. Calling this
function with a 100% min claim rate is the same as calling claimMaxGas.
*/
function claimGasAtMinClaimRate(
address _recipient,
uint256 _claimRateBips
) external onlyOwner {
IBlast(blastGasYieldContract).claimGasAtMinClaimRate(
address(this),
_recipient,
_claimRateBips
);
}
function readClaimableGas() public view returns (uint256) {
(, uint256 etherBalance, , ) = IBlast(blastGasYieldContract)
.readGasParams(address(this));
return etherBalance;
}
/********************
* *
* RAFFLE *
* *
********************/
function distributeLpFeesToLps() private {
if (lpPoolTotal == 0) {
// if no LPs have staked, distribute LP fees to the user pool
userPoolTotal += lpFeesTotal;
return;
}
if (
protocolFeeAddress != address(0) &&
lpFeesTotal >= protocolFeeThreshold
) {
uint256 protocolFee = lpFeesTotal / 10;
lpFeesTotal -= protocolFee;
protocolFeeClaimable += protocolFee;
}
for (uint256 i = 0; i < activeLpAddresses.length; i++) {
address lpAddress = activeLpAddresses[i];
LP storage lp = lpsInfo[lpAddress];
if (lp.active) {
// Calculate proportion of lp.stake to lpPoolTotal, applied to lpFeesTotal, with minimized precision loss
uint256 lpFeesShare = ((lpFeesTotal * 1e18 * lp.stake) /
lpPoolTotal) / 1e18;
lp.principal = lp.principal + lpFeesShare;
}
}
// set LpFeesTotal to 0 after distributing fees to LPs
lpFeesTotal = 0;
}
// Distribute the user pool to LP's according to their stake share of the LP pool
function distributeUserPoolToLps() private {
// TODO: handle this more elegantly + refactor lp.active
if (lpPoolTotal == 0) {
return;
}
for (uint256 i = 0; i < activeLpAddresses.length; i++) {
address lpAddress = activeLpAddresses[i];
LP storage lp = lpsInfo[lpAddress];
if (lp.active) {
// Calculate proportion of lp.stake to lpPoolTotal, applied to userPoolTotal, with minimized precision loss
uint256 userPoolShare = ((userPoolTotal * 1e18 * lp.stake) /
lpPoolTotal) / 1e18;
lp.principal = lp.principal + userPoolShare;
}
}
}
// Return the LP pool back to LP's (LP's do not lose any money)
// Make sure that distributeUserPoolToLps() is never called before this
function returnLpPoolBackToLps() private {
for (uint256 i = 0; i < activeLpAddresses.length; i++) {
address lpAddress = activeLpAddresses[i];
LP storage lp = lpsInfo[lpAddress];
// Add each LP's stake back to their principal
if (lp.active) {
lp.principal = lp.stake + lp.principal;
lp.stake = 0;
}
}
}
// Move each LP's stake from LP principal to the LP pool according to their risk percentage
function stakeLps() private {
for (uint256 i = 0; i < activeLpAddresses.length; i++) {
address lpAddress = activeLpAddresses[i];
LP storage lp = lpsInfo[lpAddress];
if (lp.active) {
// lp.principal is always dividable by 100
lp.stake = (lp.principal * lp.riskPercentage) / 100;
// lp.stake is always non-negative
lpPoolTotal += lp.stake;
lp.principal -= lp.stake;
}
}
}
function clearUserTicketPurchases() private {
for (uint256 i = 0; i < activeUserAddresses.length; i++) {
address userAddress = activeUserAddresses[i];
usersInfo[userAddress].ticketsPurchasedTotalBps = 0;
usersInfo[userAddress].active = false;
}
// After resetting usersInfo, reset the activeUserAddresses array
delete activeUserAddresses;
}
// Get the fee for making the entropy contract call
function getLotteryFee() public view returns (uint256 fee) {
fee = entropy.getFee(entropyProvider);
}
// MAIN PUBLIC FUNCTION TO RUN THE LOTTERY
// Runs the Lottery
function runLottery(bytes32 userRandomNumber) external payable {
// TIMELOCK
require(
block.timestamp >= lastLotteryEndTime + roundDurationInSeconds,
"Lottery can only be run once a day"
);
require(!lotteryLock, "Lottery is currently running!");
// acquire lottery lock
lotteryLock = true;
uint256 fee = entropy.getFee(entropyProvider);
require(msg.value >= fee, "Insufficient gas to generate random number");
(bool success, ) = msg.sender.call{value: msg.value - fee}("");
require(success, "Transfer failed");
// Request the random number from the Entropy protocol. The call returns a sequence number that uniquely
// identifies the generated random number. Callers can use this sequence number to match which request
// is being revealed in the next stage of the protocol. Since we lock the call to this function,
// we don't need to care about the sequence number
entropy.requestWithCallback{value: fee}(
entropyProvider,
userRandomNumber
);
emit LotteryRunRequested(msg.sender);
}
function getWinningTicket(
bytes32 rawRandomNumber,
uint256 max
) private pure returns (uint256) {
return (uint256(rawRandomNumber) % max) + 1;
}
function findWinnerFromUsers(
uint256 winningTicket
) private view returns (address) {
uint256 cumulativeTicketsBps = 0;
for (uint256 i = 0; i < activeUserAddresses.length; i++) {
address userAddress = activeUserAddresses[i];
User memory user = usersInfo[userAddress];
cumulativeTicketsBps += user.ticketsPurchasedTotalBps;
if (winningTicket <= cumulativeTicketsBps) {
return userAddress;
}
}
// No winner found, this should never happen
return fallbackWinner;
}
// Determines a winner, and adjusts LP's principal/stake accordingly
function determineWinnerAndAdjustStakes(bytes32 randomNumber) private {
lastLotteryEndTime = block.timestamp;
// No tickets bought
if (ticketCountTotalBps == 0) {
emit LotteryRun(lastLotteryEndTime, address(0), 0, lpPoolTotal, 0);
// Return LP Pool back to LPs
returnLpPoolBackToLps();
// Reset LP Pool before iniitalizing pool again
lpPoolTotal = 0;
stakeLps();
return;
}
// Distribute LP fees to LP's
distributeLpFeesToLps();
if (userPoolTotal >= lpPoolTotal) {
// Jackpot is fully funded by users, so winner gets the user pool and LP's get the LP pool
uint256 winningTicket = getWinningTicket(
randomNumber,
ticketCountTotalBps
);
lastWinnerAddress = findWinnerFromUsers(winningTicket);
// Calculate and store win amount, which is user pool, fees are already deducted
uint256 winAmount = userPoolTotal;
User storage winner = usersInfo[lastWinnerAddress];
winner.winningsClaimable += winAmount;
// Return the LP pool back to the LP's
returnLpPoolBackToLps();
emit LotteryRun(
lastLotteryEndTime,
lastWinnerAddress,
winningTicket,
winAmount,
winner.ticketsPurchasedTotalBps
);
} else {
// Jackpot is not fully funded by users, i.e. partially funded by LP's
uint256 winningTicket = getWinningTicket(
randomNumber,
(lpPoolTotal * 10000) / ticketPrice
);
if (winningTicket <= ticketCountTotalBps) {
// Jackpot is won by a user, so winner gets the LP pool and LP's get the user pool (but lose the LP pool)
lastWinnerAddress = findWinnerFromUsers(winningTicket);
// Distribute LP pool
uint256 winAmount = lpPoolTotal;
User storage winner = usersInfo[lastWinnerAddress];
winner.winningsClaimable += winAmount;
// Distribute user pool to the LP's
distributeUserPoolToLps();
emit LotteryRun(
lastLotteryEndTime,
lastWinnerAddress,
winningTicket,
winAmount,
winner.ticketsPurchasedTotalBps
);
} else {
// Jackpot is won by LP's, so LP's get both the user pool and LP pool
lastWinnerAddress = address(0);
// Distribute user pool to the LP's
distributeUserPoolToLps();
returnLpPoolBackToLps();
emit LotteryRun(
lastLotteryEndTime,
lastWinnerAddress,
winningTicket,
lpPoolTotal,
0
);
}
}
// Reset ticket purchases and lottery variables for the next round
clearUserTicketPurchases();
userPoolTotal = 0;
lpPoolTotal = 0;
ticketCountTotalBps = 0;
// Reset fee accumulators, LP fee total reset in its own function
allFeesTotal = 0;
referralFeesTotal = 0;
// Stake the LP's
stakeLps();
}
// PUBLIC DEPOSIT / PURCHASE FUNCTIONS
// Called by LP to: deposit initial principal, deposit more principal, or adjust their riskPercentage
// Adjusts principal and riskPercentage instantly
// Does not take adjust stake amount or pool size until next run
function lpDeposit(uint256 riskPercentage, uint256 value) public {
require(
riskPercentage > 0 && riskPercentage <= 100,
"Invalid risk percentage"
);
require(
value % ticketPrice == 0,
"Invalid deposit amount, must be a multiple of minimum ticket size"
);
require(
value == 0 || lpPoolTotal + value <= lpPoolCap,
"Deposit exceeds LP pool cap"
);
require(!lotteryLock, "Lottery is currently running!");
require(
value == 0 || activeLpAddresses.length < lpLimit,
"Max LP limit reached"
);
require(
value == 0 || value >= minLpDeposit,
"LP deposit less than minimum"
);
require(
blastToken.transferFrom(msg.sender, address(this), value),
"ERC20: transfer failed"
);
LP storage lp = lpsInfo[msg.sender];
if (!lp.active) {
require(
value > 0,
"Invalid deposit amount, must be strictly positive for new LP"
);
lp.active = true;
// Add newly active LP address
activeLpAddresses.push(msg.sender);
}
lp.principal += value;
lp.riskPercentage = riskPercentage;
emit LpDeposit(msg.sender, value, riskPercentage);
}
// Purchase tickets for user
function purchaseTickets(address referrer, uint256 value) public {
require(allowPurchasing, "Purchasing tickets not allowed");
require(
value > 0 && value % ticketPrice == 0,
"Invalid purchase amount, must be positive and a multiple of minimum ticket size"
);
require(!lotteryLock, "Lottery is currently running!");
require(
activeUserAddresses.length < userLimit,
"Max user limit reached"
);
// Require that the purchase is made with the correct amount of tokens
require(
blastToken.transferFrom(msg.sender, address(this), value),
"ERC20: transfer failed"
);
// This is in "Bps", so a 0.001 ETH ticket purchase at feeBps = 500 (or 5%) would result in 9500
uint256 ticketsPurchasedBps = (value / ticketPrice) * (10000 - feeBps);
User storage user = usersInfo[msg.sender];
if (!user.active) {
user.active = true;
// Add new user address, will be reset when lottery ends
activeUserAddresses.push(msg.sender);
}
// Calculate fees. Total fees are inclusive of referrer fees, if there are any
uint256 allFeeAmount = (value * feeBps) / 10000;
// Referrer fee is active only if a valid referrer address is provided. otherwise, no referrer fee is taken from the total fee, aka LPs get all the fees
uint256 referralFeeAmount = (referrer != address(0))
? (value * referralFeeBps) / 10000
: 0;
uint256 lpFeeAmount = allFeeAmount - referralFeeAmount;
// Add entry to user pool. Note pool is post-fee
userPoolTotal += (value * (10000 - feeBps)) / 10000;
// Add to total accumulators
allFeesTotal += allFeeAmount;
referralFeesClaimable[referrer] += referralFeeAmount;
referralFeesTotal += referralFeeAmount;
lpFeesTotal += lpFeeAmount;
user.ticketsPurchasedTotalBps += ticketsPurchasedBps;
ticketCountTotalBps += ticketsPurchasedBps;
emit UserTicketPurchase(msg.sender, ticketsPurchasedBps);
}
// PUBLIC WITHDRAWAL FUNCTIONS
// Called by a user to withdraw their jackpot winnings
function withdrawWinnings() public {
User storage user = usersInfo[msg.sender];
require(user.winningsClaimable > 0, "No winnings to withdraw");
uint256 transferAmount = user.winningsClaimable;
emit UserWinWithdrawal(msg.sender, transferAmount);
// Reset stored amount before sending to prevent re-entrance
user.winningsClaimable = 0;
bool success = blastToken.transfer(msg.sender, transferAmount);
require(success, "Transfer failed");
}
// Called by a user to withdraw their referral fees
function withdrawReferralFees() public {
require(
referralFeesClaimable[msg.sender] > 0,
"No referral fees to withdraw"
);
uint256 transferAmount = referralFeesClaimable[msg.sender];
emit UserReferralFeeWithdrawal(msg.sender, transferAmount);
// Reset stored amount before sending to prevent re-entrance
referralFeesClaimable[msg.sender] = 0;
bool success = blastToken.transfer(msg.sender, transferAmount);
require(success, "Transfer failed");
}
// Only callable by protocolFeeAddress to withdraw protocol fees
function withdrawProtocolFees() external onlyOwner {
require(protocolFeeClaimable > 0, "No protocol fees to withdraw");
uint256 transferProtocolFeeAmount = protocolFeeClaimable;
emit ProtocolFeeWithdrawal(protocolFeeClaimable);
// Reset stored amount before sending to prevent re-entrance
protocolFeeClaimable = 0;
bool success = blastToken.transfer(
msg.sender,
transferProtocolFeeAmount
);
require(success, "Transfer failed");
}
// Called by an LP to withdrawl all of their principal when they have nothing staked in the LP pool for the current lottery.
// If the LP has a positive amount staked in the current LP pool, we will set their riskPercentage to 0 so they will be able
// to withdraw after the current lottery finishes (by calling this function again).
function withdrawAllLP() public {
LP storage lp = lpsInfo[msg.sender];
// Ensure the LP is active
require(lp.active, "LP is not active");
// Ensure the LP does not have anything staked in the current lottery
// If they do, then set their risk percentage to 0 so they can withdraw after the current lottery finishes
if (lp.stake > 0) {
lp.riskPercentage = 0;
return;
}
// LP has 0 stake now so it's ok to proceed with the withdrawal
uint256 principalAmount = lp.principal;
emit LpPrincipalWithdrawal(msg.sender, principalAmount);
// Reset numbers first to prevent re-entrance
lp.riskPercentage = 0;
lp.principal = 0;
lp.active = false;
// Find LP address index in activeLpAddresses
int256 lpIndex = -1;
for (uint256 i = 0; i < activeLpAddresses.length; i++) {
if (activeLpAddresses[i] == msg.sender) {
lpIndex = int256(i);
}
}
require(lpIndex != -1, "LP index not found");
// Remove LP address from activeLpAddresses (by replacing it with the last element and popping the last element)
activeLpAddresses[uint256(lpIndex)] = activeLpAddresses[
activeLpAddresses.length - 1
];
activeLpAddresses.pop();
// Transfer the principal back to the LP
bool success = blastToken.transfer(msg.sender, principalAmount);
require(success, "Transfer failed");
}
/****************************
* *
* ADMIN CONTROLS *
* *
****************************/
function setTicketPrice(uint256 _newTicketPrice) external onlyOwner {
ticketPrice = _newTicketPrice;
}
function setRoundDurationInSeconds(
uint256 _newDuration
) external onlyOwner {
roundDurationInSeconds = _newDuration;
}
function setReferralFeeBps(uint256 _referralFeeBps) external onlyOwner {
require(
_referralFeeBps <= feeBps,
"Referral bps should not exceed fee bps"
);
referralFeeBps = _referralFeeBps;
}
function setFeeBps(uint256 _feeBps) external onlyOwner {
require(_feeBps <= 1500, "Fee bps should not exceed 1500");
feeBps = _feeBps;
}
function setLpPoolCap(uint256 _cap) external onlyOwner {
lpPoolCap = _cap;
}
function setProtocolFeeAddress(
address _protocolFeeAddress
) external onlyOwner {
protocolFeeAddress = _protocolFeeAddress;
}
function setProtocolFeeThreshold(uint256 _newThreshold) external onlyOwner {
protocolFeeThreshold = _newThreshold;
}
// break glass mechanism in case entropy contract does not callback
function forceReleaseLotteryLock() external onlyOwner {
lotteryLock = false;
}
function setFallbackWinner(address _fallbackWinner) external onlyOwner {
fallbackWinner = _fallbackWinner;
}
function setLpLimit(uint256 _lpLimit) external onlyOwner {
lpLimit = _lpLimit;
}
function setUserLimit(uint256 _userLimit) external onlyOwner {
userLimit = _userLimit;
}
function setMinLpDeposit(uint256 _minDeposit) external onlyOwner {
minLpDeposit = _minDeposit;
}
function setAllowPurchasing(bool _allow) external onlyOwner {
allowPurchasing = _allow;
}
}
/* This builds upon a MIT-licensed contract by the PEVL hackathon team, led by Patrick Lung, deployed on testnet at 0x0278a964dC3275274bD845B936cE2e0b09c8B827
The contract was modified significantly by Patrick Lung and other collaborators, and last deployed with MIT license at 0xf9d524576646d718e4f5f5bade17082d9ecf25d0
Any changes not in the above MIT-licensed contracts are under BUSL-1.1.
Business Source License 1.1
License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved.
"Business Source License" is a trademark of MariaDB Corporation Ab.
-----------------------------------------------------------------------------
Parameters
Licensor: Coordination Inc.
Licensed Work: Megapot Raffle (Lottery.sol)
The Licensed Work is (c) 2024 Coordination Inc.
Change Date: 2028-05-27
Change License: GNU General Public License v2.0 or later
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment