Smart Contract
BagLottery
A.c649103ebbc38926.BagLottery
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}