Smart Contract
ProjectMetadata
A.0b80e42aaab305f0.ProjectMetadata
1access(all)contract ProjectMetadata {
2 // ProjectMetadataRandomNFT
3 access(all)struct RatioRandomNFTItem {
4 access(all)let id: UInt64
5 access(contract) let image: String
6 access(contract) let nftMetadata: {String:String}
7 access(contract) let nftIDs: [UInt64]
8 access(contract) let maxSupply: UInt64
9 access(contract) let ratio: UFix64
10
11 init(id: UInt64, image: String, maxSupply: UInt64, nftMetadata: {String:String}, ratio: UFix64) {
12 pre {
13 ratio <= 1.0: "ratio sould be <= 100%"
14 }
15 self.image = image
16 self.nftIDs = []
17 self.maxSupply = maxSupply
18 self.ratio = ratio
19 self.nftMetadata = nftMetadata
20 self.id = id
21 }
22
23 access(all)fun addNFT(_ nftID: UInt64) {
24 self.nftIDs.append(nftID)
25 }
26
27 access(all)fun getImage(): String {
28 return self.image
29 }
30
31 access(all)fun getRatio(): UFix64 {
32 return self.ratio
33 }
34
35 access(all)fun getNftMetadata(): {String:String} {
36 return self.nftMetadata
37 }
38
39 access(all)fun getNftIDs(): [UInt64] {
40 return self.nftIDs
41 }
42
43 access(all)fun getMaxSupply(): UInt64 {
44 return self.maxSupply
45 }
46
47 access(all)fun getTotalSupply(): UInt64 {
48 return UInt64(self.nftIDs.length)
49 }
50 }
51 access(all)struct RatioRandomNFT {
52 access(all)let items: [RatioRandomNFTItem]
53
54 init(images: [String], maxSupplies: [UInt64], nftMetadatas: [{String:String}], ratios: [UFix64]) {
55 pre {
56 images.length == maxSupplies.length: "maxSupplies length is invalid"
57 images.length == nftMetadatas.length: "nftMetadatas length is invalid"
58 images.length == ratios.length: "ratios length is invalid"
59 }
60 self.items = []
61 var i = 0
62 var totalRatio = 0.0
63 while i < images.length {
64 let randomItem = RatioRandomNFTItem(id: UInt64(i+1), image: images[i], maxSupply: maxSupplies[i], nftMetadata: nftMetadatas[i], ratio: ratios[i])
65 self.items.append(randomItem)
66 totalRatio = totalRatio + randomItem.getRatio()
67 i = i + 1
68 }
69
70 if totalRatio != 1.0 {
71 panic("Total raito must be equal 100%")
72 }
73 }
74
75 access(all)fun getImages(): [String] {
76 let res: [String] = []
77 for item in self.items {
78 res.append(item.getImage())
79 }
80 return res
81 }
82
83 access(all)fun getNftMetadatas(): [{String:String}] {
84 let res: [{String:String}] = []
85 for item in self.items {
86 res.append(item.getNftMetadata())
87 }
88 return res
89 }
90
91 access(all)fun updateItem(itemId: UInt64, item: RatioRandomNFTItem) {
92 var i = 0
93 while i < self.items.length {
94 if self.items[i].id == itemId {
95 self.items[i] = item
96 return
97 }
98 i = i + 1
99 }
100 }
101
102 access(contract) fun getRandomByRatio(_ items: [RatioRandomNFTItem]): RatioRandomNFTItem {
103 let defaultItem = items[0]
104 let itemLen = items.length
105 var i = 0
106 var cumSum = 0.0
107 let randomNum: UFix64 = UFix64(revertibleRandom<UInt64>() % 1000000) / 1000000.0 // get random number from 0.0 to 0.99999
108 while(i < itemLen) {
109 cumSum = cumSum + items[i].getRatio()
110 if randomNum <= cumSum {
111 return items[i]
112 }
113 i = i + 1
114 }
115 return defaultItem
116 }
117
118 access(all)fun getRaitoRandomItemForMint(_ quantity: UInt64): [RatioRandomNFTItem] {
119 let randomItems: [RatioRandomNFTItem] = []
120
121 while UInt64(randomItems.length) < quantity {
122 // get images valid
123 let itemValid: [RatioRandomNFTItem] = []
124 for item in self.items {
125 if item.getMaxSupply() > item.getTotalSupply() {
126 itemValid.append(item)
127 }
128 }
129
130 if itemValid.length == 0 {
131 panic("RANDOM_NFT_IS_SOLD_OUT")
132 }
133
134 // prepare random image
135 let itemRandom = self.getRandomByRatio(itemValid)
136 randomItems.append(itemRandom)
137 }
138 return randomItems
139 }
140
141 access(all)fun addNFT(itemId: UInt64, nftID: UInt64) {
142 var i = 0
143 while i < self.items.length {
144 let item: RatioRandomNFTItem = self.items[i]
145 if item.id == itemId {
146 item.addNFT(nftID)
147 self.items[i] = item
148 }
149 i = i + 1
150 }
151 }
152 }
153
154 // LotteryRandom
155 access(all)event LotteryRandom(nftID: UInt64, nftType: String, nftOwner: Address, lotteryNumber: UInt64, winner: Bool)
156 access(all)struct LotteryItem {
157 access(all)let nftID: UInt64
158 access(all)let nftOwner: Address
159 access(all)let timestamp: UFix64
160 access(all)let lotteryNumber: UInt64
161 access(all)let nftType: String
162
163 init(
164 nftID: UInt64,
165 nftOwner: Address,
166 nftType: String,
167 lotteryNumber: UInt64,
168 ) {
169 self.nftID = nftID
170 self.nftOwner = nftOwner
171 self.lotteryNumber = lotteryNumber
172 self.nftType = nftType
173 self.timestamp = getCurrentBlock().timestamp
174 }
175 }
176 access(all)struct LotteryRandomNFT {
177 access(all)let lotteryItems: [LotteryItem]
178 access(all)let luckyNumbers: [UInt64]
179 access(all)let lotteryNumberNotUse: [UInt64]
180 access(all)let nftMetadata: {String:String}
181 access(self) var winner: LotteryItem?
182
183 init(nftMetadata: {String:String}, luckyNumbers: [UInt64], totalNumber: UInt64) {
184 // validate lucky numbers
185 for luckyNumber in luckyNumbers {
186 if luckyNumber < 1 || luckyNumber > totalNumber {
187 panic("Lucky number is invalid: ".concat(luckyNumber.toString()))
188 }
189 }
190
191 self.winner = nil
192 self.lotteryItems = []
193 self.nftMetadata = nftMetadata
194 self.luckyNumbers = luckyNumbers
195
196 self.lotteryNumberNotUse = []
197 var i = UInt64(1)
198 while i <= totalNumber {
199 self.lotteryNumberNotUse.append(i)
200 i = i + 1
201 }
202 }
203
204 access(all)fun isNftUsed(nftID: UInt64, nftType: String): Bool {
205 for item in self.lotteryItems {
206 if item.nftType == nftType && item.nftID == nftID {
207 return true
208 }
209 }
210 return false
211 }
212
213 access(self) fun getLotteryNumberIndex(): Int {
214 let randomNumber = revertibleRandom<UInt64>()
215 let randomNum = UFix64(revertibleRandom<UInt64>() % 1000000) / 1000000.0 // get random number from 0.0 to 0.99999
216 let randomIndex = Int(randomNum * UFix64(self.lotteryNumberNotUse.length)) // get random number from 0 to lotteryNumberNotUse.length - 1
217 return randomIndex
218 }
219
220 // create a lottery number and update winner
221 access(all)fun tokenGate(nftID: UInt64, nftType: String, nftOwner: Address): Void {
222 if self.isNftUsed(nftID: nftID, nftType: nftType) {
223 return
224 }
225 let lotteryNumberIndex = self.getLotteryNumberIndex();
226 let lotteryNumber = self.lotteryNumberNotUse[lotteryNumberIndex]
227 self.lotteryNumberNotUse.remove(at: lotteryNumberIndex)
228 let item = LotteryItem(nftID: nftID, nftOwner: nftOwner, nftType: nftType,lotteryNumber: lotteryNumber)
229 self.lotteryItems.append(item)
230 if self.luckyNumbers.contains(lotteryNumber) {
231 self.winner = item
232 emit LotteryRandom(nftID: nftID, nftType: nftType, nftOwner: nftOwner, lotteryNumber: lotteryNumber, winner: true)
233 } else {
234 emit LotteryRandom(nftID: nftID, nftType: nftType, nftOwner: nftOwner, lotteryNumber: lotteryNumber, winner: false)
235 }
236 }
237
238 access(all)fun getWinner(): LotteryItem? {
239 return self.winner
240 }
241
242 access(all)fun resetGate() {
243 while self.lotteryItems.length != 0 {
244 self.lotteryItems.remove(at: 0)
245 }
246 }
247 }
248}