Smart Contract

BagLottery

A.c649103ebbc38926.BagLottery

Valid From

130,487,420

Deployed

1w ago
Feb 20, 2026, 09:25:16 AM UTC

Dependents

8 imports
1import FungibleToken from 0xf233dcee88fe0abe
2import FlowToken from 0x1654653399040a61
3import Bag from 0xc649103ebbc38926
4import BagRegistry from 0xc649103ebbc38926
5
6access(all) contract BagLottery {
7
8    /* --- Events --- */
9    access(all) event NewLotteryCreated(lotteryID: UInt64)
10    access(all) event LotteryVaultFunded(amount: UFix64)
11    access(all) event LotteryResolvedAndPrizeDistributed(lotteryID: UInt64, nftId: UInt64, winnerAddress: Address, amount: UFix64)
12    access(all) event BagLotteryInitialized()
13
14    /* --- Storage Paths --- */
15    access(all) let AdminStoragePath: StoragePath
16
17    access(all) var totalLottery: UInt64
18    access(self) let lotteryVault: @FlowToken.Vault
19
20    /* --- Lottery Resource --- */
21    access(all) resource Lottery {
22        access(all) let id: UInt64
23        access(all) var winnerNFTId: UInt64
24        access(all) var winnerAddress: Address?
25        access(all) var winnings: UFix64
26        access(all) var isResolved: Bool
27        access(all) var prizeDistributed: Bool
28        
29        init() {
30            self.id = BagLottery.totalLottery
31            self.winnerNFTId = 0
32            self.winnerAddress = nil
33            self.winnings = 0.0
34            self.isResolved = false
35            self.prizeDistributed = false
36        }
37
38        access(all) fun updateLotteryDetails(nftId: UInt64, address: Address, amount:UFix64) {
39            pre {
40                !self.isResolved: "Details are already set!!"
41            }
42            self.winnerNFTId = nftId
43            self.winnerAddress = address
44            self.winnings = amount
45            self.prizeDistributed = true
46        }
47
48        access(all) fun markAsResolved() {
49            self.isResolved = true
50        }
51    }
52
53    access(all) resource Admin {
54        access(all) let lotteries: @{UInt64: Lottery} 
55
56        access(all) fun createLottery() {
57            BagLottery.totalLottery = BagLottery.totalLottery + 1
58            let newLottery <- create Lottery()
59            emit NewLotteryCreated(lotteryID: newLottery.id)
60            self.lotteries[newLottery.id] <-! newLottery
61        }
62
63        access(all) fun fundPrizePool(amount: @{FungibleToken.Vault}) {
64            let fundedAmount = amount.balance
65            BagLottery.lotteryVault.deposit(from: <- amount)
66            emit LotteryVaultFunded(amount: fundedAmount)
67        }
68
69        access(all) fun resolveLottery(lotteryID: UInt64) {
70            let totalPrize = BagLottery.getLotteryVaultBalance()
71            assert(totalPrize > 0.0, message: "Prize pool is empty")
72
73            let lotteryRef = self.borrowLottery(lotteryID: lotteryID) 
74                ?? panic("Lottery not found with ID: ".concat(lotteryID.toString()))
75            
76            assert(!lotteryRef.isResolved, message:"Lottery has already been resolved")
77
78            // Resolve lottery
79            let totalNFTs = BagLottery.getBagTotalSupply()
80
81            // Get winning NFT
82            let winner_NFT_Id = BagLottery.generateRandomNumber(upperBound: totalNFTs)  
83
84            // Get winning NFT holder Address
85            let registerAddress = Bag.registryAddress
86            let registryRef = getAccount(registerAddress).contracts.borrow<&BagRegistry>(name: "BagRegistry") ?? panic("")
87            let winnerAddress = registryRef.getHolder(bagId: winner_NFT_Id)!
88
89            // Winner 
90            // 100% prizes is distributed to one Bag holder        
91            let winnerVault <- BagLottery.lotteryVault.withdraw(amount: totalPrize) 
92            let winnerReceiver = BagLottery.getFlowTokenReceiver(user:winnerAddress)          
93            winnerReceiver.deposit(from: <- winnerVault)
94
95            let bag = Bag.borrowNFT(ownerAddress: winnerAddress, nftId: winner_NFT_Id)
96            bag.incrementWinCount()
97            
98            lotteryRef.updateLotteryDetails(nftId: winner_NFT_Id, address: winnerAddress, amount:totalPrize)
99            lotteryRef.markAsResolved()
100
101            emit LotteryResolvedAndPrizeDistributed(lotteryID: lotteryID, nftId: winner_NFT_Id, winnerAddress: winnerAddress, amount: totalPrize)
102        }
103
104        access(all) fun borrowLottery(lotteryID: UInt64): &Lottery? {
105            return &self.lotteries[lotteryID]
106        }
107
108        access(all) fun getAllLotteryIDs(): [UInt64] {
109            return self.lotteries.keys
110        }
111
112        init() {
113            self.lotteries <- {}
114        }
115    }
116
117    access(contract) fun getAdmin(): &Admin {
118        return self.account.storage.borrow<&Admin>(from: self.AdminStoragePath)
119            ?? panic("Could not borrow a reference to a Admin")
120    }
121    
122    access(self) fun generateRandomNumber(upperBound: UInt64): UInt64 {
123        assert(upperBound > 0, message: "Upper bound must be greater than 0")
124        let randomValue: UInt64 = revertibleRandom<UInt64>()
125        let rand = (randomValue % upperBound) + 1
126        return rand
127    }
128
129    access(all) fun borrowLottery(lotteryID: UInt64): &Lottery {
130        return self.getAdmin().borrowLottery(lotteryID: lotteryID) 
131            ?? panic("Lottery not found with ID: ".concat(lotteryID.toString()))
132    }
133
134    access(all) fun getAllLotteries(): [&BagLottery.Lottery]{
135        let lotteryReferences: [&BagLottery.Lottery] = []
136        let adminRef = self.getAdmin()
137        let ids = adminRef.getAllLotteryIDs()
138        for id in ids{
139            lotteryReferences.append(self.borrowLottery(lotteryID: id))
140        }
141        return lotteryReferences
142    }
143
144    access(all) fun getFlowTokenReceiver(user:Address): &{FungibleToken.Receiver}{
145        return getAccount(user)
146        .capabilities
147        .borrow<&{FungibleToken.Receiver}>(/public/flowTokenReceiver) 
148        ?? panic("Could not borrow Bag Team Flow Token receiver reference")  
149    }
150
151    /* --- View Functions --- */
152
153    access(all) view fun getBagTotalSupply(): UInt64 {
154        return Bag.totalSupply
155    }
156
157    access(all) view fun getLotteryVaultBalance(): UFix64{
158        return BagLottery.lotteryVault.balance
159    }
160
161    init() {
162        self.totalLottery = 0
163        self.lotteryVault <- FlowToken.createEmptyVault(vaultType: Type<@FlowToken.Vault>())
164        self.AdminStoragePath = /storage/BagLotteryAdmins
165
166        let admin: @Admin <- create Admin()
167        self.account.storage.save(<- admin, to: self.AdminStoragePath)
168
169        emit BagLotteryInitialized()
170    }
171}