The simplest & fairest lottery.
Let's be honest - web3 has a bad rap.
With so many scams rampant, it's easy to assume this is a scam as well.
If that's how you feel, you shouldn't participate - always trust yourself and DYOR.
This page is dedicated to explaining exactly how Flow Lottery works, so you can feel more informed if you do decide to play.
It all happens on-chain - specifically on the Flow blockchain.
Why? Because it's user-friendly and very scalable. Things like gas-less transactions (subsidized by wallets) and real on-chain randomness make it the perfect home for this project.
OK, but how does it actually work?
Flow Lottery's first draw is happening on December 25th, 2023. As part of this special introductory launch, 5 lucky tickets will share the pot, each winning a different prize. See the table below for prizes:
Prizes | Payout |
---|---|
Jackpot | 1.00 |
2nd Prize | 1.00 |
3rd prize | 1.00 |
4th prize | 1.00 |
5th prize | 1.00 |
These payouts will continue to increase with ticket sales.
The best way to understand how it works is to walk through the contract.
You can read the full contract here: FlowLottery Contract
For the special Christmas event, the organizers on the 25th of December will execute a special payout function (resolveWinner) 5 times - once for each prize.
As you can see, every time the resolveWinner()
function executes, it picks a random prize winner in ascending order (from smallest, to largest). The 4 smallest prizes share roughly 30% of the pot, the rest goes to the jackpot winner.
// christmas special
pub fun resolveWinner() {
let currentLotteryDetails: &LotteryDetails = self.borrowCurrentLotteryDetails()!
assert(currentLotteryDetails.entries.length > 0, message: "No one has entered the lottery yet!")
let numDone: Int = currentLotteryDetails.winners.length
let percentAmounts: {Int: UFix64} = {
0: 0.01,
1: 0.02,
2: 0.07,
3: 0.20,
4: 1.00
}
// get amount
let amount: UFix64 = FlowLottery.pot.balance * percentAmounts[numDone]!
let hitJackpot: Bool = numDone == 4
// get the winner
let randomWinnerIndex: UInt64 = FlowLottery.getRandom(min: 0, max: UInt64(currentLotteryDetails.entries.length) - 1)
let winner: Address = currentLotteryDetails.entries[randomWinnerIndex]
// remove rake
// 2.5% total:
// 0.5% is for the platform (development + marketing)
// 2% rollover gets immediately deposited back into the pot for future drawings
let winnings: @FungibleToken.Vault <- FlowLottery.pot.withdraw(amount: amount)
let rollover: @FungibleToken.Vault <- winnings.withdraw(amount: amount * 0.02)
let platformTax: @FungibleToken.Vault <- winnings.withdraw(amount: amount * 0.005)
let platformVault: &FlowToken.Vault{FungibleToken.Receiver} = FlowLottery.account.getCapability(/public/flowTokenReceiver).borrow<&FlowToken.Vault{FungibleToken.Receiver}>()!
platformVault.deposit(from: <- platformTax)
// deposit winnings
let winnerFlowVault: &FlowToken.Vault{FungibleToken.Receiver} = getAccount(winner).getCapability(/public/flowTokenReceiver)
.borrow<&FlowToken.Vault{FungibleToken.Receiver}>()
?? panic("User does not have a Flow Token vault set up.")
winnerFlowVault.deposit(from: <- winnings)
// remove winner's ticket and add them as a winner
currentLotteryDetails.addWinner(address: winner, amount: amount, removeAtIndex: randomWinnerIndex)
// reset & automatically start a new lottery
if hitJackpot {
self.reset()
}
// deposit rollover
FlowLottery.pot.deposit(from: <- rollover)
emit LotteryWinner(winner: winner, amount: amount, winningNumber: randomWinnerIndex)
}
}
You can read the full contract here: FlowLottery Contract
All funds are stored in the smart contract and cannot be touched.
They can only be moved when the resolveWinner()
function is run.
When that happens, the on-chain randomizer will select a winning ticket (as shown above) and send funds from the pot to the winner.