Flow Lottery

The simplest & fairest lottery.

Provably Fair.100% on-chain


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.

However ...

This page is dedicated to explaining exactly how Flow Lottery works, so you can feel more informed if you do decide to play.

How it works

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:

2nd Prize1.00
3rd prize1.00
4th prize1.00
5th prize1.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)
                        ?? 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 {

    // deposit rollover
    FlowLottery.pot.deposit(from: <- rollover)

    emit LotteryWinner(winner: winner, amount: amount, winningNumber: randomWinnerIndex)

You can read the full contract here: FlowLottery Contract

How Funds are Stored

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.

Join the fun