Smart Contract
CollectorMinter
A.7c8995e83c4b1843.CollectorMinter
1// SPDX-License-Identifier: UNLICENSED
2
3import FungibleToken from 0xf233dcee88fe0abe
4import NonFungibleToken from 0x1d7e57aa55817448
5import DapperUtilityCoin from 0xead892083b3e2c6c
6import Collector from 0x7c8995e83c4b1843
7
8pub contract CollectorMinter {
9 pub event ContractInitialized(merchantAccount: Address)
10
11 pub let AdminStoragePath: StoragePath
12
13 pub var privateSaleMaxTokens: UInt64
14 pub var privateSalePrice: UFix64
15 pub var presaleMaxTokens: UInt64
16 pub var presalePrice: UFix64
17 pub var publicSaleMaxTokens: UInt64
18 pub var publicSalePrice: UFix64
19
20 pub var privateSaleRegistrationOpen: Bool
21 pub var presaleRegistrationOpen: Bool
22
23 access(self) var privateSaleAccounts: {Address: UInt64}
24 access(self) var presaleAccounts: {Address: UInt64}
25 access(self) var publicSaleAccounts: {Address: UInt64}
26
27 pub var merchantAccount: Address
28
29 pub fun registerForPrivateSale(buyer: Address) {
30 pre {
31 self.privateSaleRegistrationOpen == true:
32 "Private sale registration is closed"
33 self.privateSaleAccounts[buyer] == nil:
34 "Address already registered for the private sale"
35 }
36
37 self.privateSaleAccounts[buyer] = self.privateSaleMaxTokens
38 }
39
40 pub fun privateSaleMintNFTWithDUC(buyer: Address, setID: UInt64, paymentVault: @FungibleToken.Vault, numberOfTokens: UInt64, merchantAccount: Address) {
41 pre {
42 self.privateSaleAccounts[buyer]! >= 0:
43 "Requesting account is not whitelisted"
44 numberOfTokens <= self.privateSaleMaxTokens:
45 "Purchase amount exceeds maximum allowed"
46 self.privateSaleAccounts[buyer]! >= numberOfTokens:
47 "Purchase amount exceeds maximum buyer allowance"
48 paymentVault.balance >= UFix64(numberOfTokens) * self.privateSalePrice:
49 "Insufficient payment amount"
50 paymentVault.getType() == Type<@DapperUtilityCoin.Vault>():
51 "Payment type not DapperUtilityCoin"
52 self.merchantAccount == merchantAccount:
53 "Mismatching merchant account"
54 }
55
56 let admin = self.account.borrow<&Collector.Admin>(from: Collector.AdminStoragePath)
57 ?? panic("Could not borrow a reference to the collector admin")
58
59 let set = admin.borrowSet(id: setID)
60
61 // Check set availability
62 if (set.getAvailableTemplateIDs().length == 0) { panic("Set is empty") }
63
64 // Check set eligibility
65 if (set.isPublic) { panic("Cannot mint public set with privateSaleMintNFTWithDUC") }
66
67 // Get DUC receiver reference of Collector merchant account
68 let merchantDUCReceiverRef = getAccount(self.merchantAccount).getCapability<&{FungibleToken.Receiver}>(/public/dapperUtilityCoinReceiver)
69 assert(merchantDUCReceiverRef.borrow() != nil, message: "Missing or mis-typed merchant DUC receiver")
70
71 // Deposit DUC to Collector merchant account DUC Vault (it's then forwarded to the main DUC contract afterwards)
72 merchantDUCReceiverRef.borrow()!.deposit(from: <-paymentVault)
73
74 // Get buyer collection public to receive Collector
75 let recipient = getAccount(buyer)
76 let NFTReceiver = recipient.getCapability(Collector.CollectionPublicPath)
77 .borrow<&{NonFungibleToken.CollectionPublic}>()
78 ?? panic("Could not get receiver reference to the NFT collection")
79
80 // Mint Collector NFTs
81 var mintCounter = numberOfTokens
82 while(mintCounter > 0) {
83 admin.mintNFT(recipient: NFTReceiver, setID: setID)
84 mintCounter = mintCounter - 1
85 }
86
87 // Remove utilized spots
88 self.privateSaleAccounts[buyer] = self.privateSaleAccounts[buyer]! - numberOfTokens
89 }
90
91 pub fun registerForPresale(buyer: Address) {
92 pre {
93 self.presaleRegistrationOpen == true:
94 "Presale registration is closed"
95 self.presaleAccounts[buyer] == nil:
96 "Address already registered for the presale"
97 }
98
99 self.presaleAccounts[buyer] = self.presaleMaxTokens
100 }
101
102 pub fun presaleMintNFTWithDUC(buyer: Address, setID: UInt64, paymentVault: @FungibleToken.Vault, numberOfTokens: UInt64, merchantAccount: Address) {
103 pre {
104 self.presaleAccounts[buyer]! >= 0:
105 "Requesting account is not whitelisted"
106 numberOfTokens <= self.presaleMaxTokens:
107 "Purchase amount exceeds maximum allowed"
108 self.presaleAccounts[buyer]! >= numberOfTokens:
109 "Purchase amount exceeds maximum buyer allowance"
110 paymentVault.balance >= UFix64(numberOfTokens) * self.presalePrice:
111 "Insufficient payment amount"
112 paymentVault.getType() == Type<@DapperUtilityCoin.Vault>():
113 "Payment type not DapperUtilityCoin"
114 self.merchantAccount == merchantAccount:
115 "Mismatching merchant account"
116 Collector.totalSupply < 3506:
117 "Reached max capacity"
118 }
119
120 let admin = self.account.borrow<&Collector.Admin>(from: Collector.AdminStoragePath)
121 ?? panic("Could not borrow a reference to the collector admin")
122
123 let set = admin.borrowSet(id: setID)
124
125 // Check set availability
126 if (set.getAvailableTemplateIDs().length == 0) { panic("Set is empty") }
127
128 // Check set eligibility
129 if (set.isPublic) { panic("Cannot mint public set with presaleMintNFTWithDUC") }
130
131 // Get DUC receiver reference of Collector merchant account
132 let merchantDUCReceiverRef = getAccount(self.merchantAccount).getCapability<&{FungibleToken.Receiver}>(/public/dapperUtilityCoinReceiver)
133 assert(merchantDUCReceiverRef.borrow() != nil, message: "Missing or mis-typed merchant DUC receiver")
134
135 // Deposit DUC to Collector merchant account DUC Vault (it's then forwarded to the main DUC contract afterwards)
136 merchantDUCReceiverRef.borrow()!.deposit(from: <-paymentVault)
137
138 // Get buyer collection public to receive Collector
139 let recipient = getAccount(buyer)
140 let NFTReceiver = recipient.getCapability(Collector.CollectionPublicPath)
141 .borrow<&{NonFungibleToken.CollectionPublic}>()
142 ?? panic("Could not get receiver reference to the NFT collection")
143
144 // Mint Collector NFTs
145 var mintCounter = numberOfTokens
146 while(mintCounter > 0) {
147 admin.mintNFT(recipient: NFTReceiver, setID: setID)
148 mintCounter = mintCounter - 1
149 }
150
151 // Remove utilized spots
152 self.presaleAccounts[buyer] = self.presaleAccounts[buyer]! - numberOfTokens
153 }
154
155 pub fun publicSaleMintNFTWithDUC(buyer: Address, setID: UInt64, paymentVault: @FungibleToken.Vault, numberOfTokens: UInt64, merchantAccount: Address) {
156 pre {
157 numberOfTokens <= self.publicSaleMaxTokens:
158 "Purchase amount exeeds maximum allowed"
159 paymentVault.balance >= UFix64(numberOfTokens) * self.publicSalePrice:
160 "Insufficient payment amount"
161 paymentVault.getType() == Type<@DapperUtilityCoin.Vault>():
162 "Payment type not DapperUtilityCoin"
163 self.merchantAccount == merchantAccount:
164 "Mismatching merchant account"
165 Collector.totalSupply < 3506:
166 "Reached max capacity"
167 }
168
169 // Add address to public sale accounts list
170 if (self.publicSaleAccounts[buyer] == nil) {
171 self.publicSaleAccounts[buyer] = self.publicSaleMaxTokens
172 }
173
174 // Check buyer hasn't exceeded their allowance
175 if (self.publicSaleAccounts[buyer]! < numberOfTokens) {
176 panic("Purchase amount exceeds maximum buyer allowance")
177 }
178
179 let admin = self.account.borrow<&Collector.Admin>(from: Collector.AdminStoragePath)
180 ?? panic("Could not borrow a reference to the collector admin")
181
182 let set = admin.borrowSet(id: setID)
183
184 // Check set availability
185 if (set.getAvailableTemplateIDs().length == 0) { panic("Set is empty") }
186
187 // Check set eligibility
188 if (!set.isPublic) { panic("Cannot mint private set with publicSaleMintNFTWithDUC") }
189
190 // Get DUC receiver reference of Collector merchant account
191 let merchantDUCReceiverRef = getAccount(self.merchantAccount).getCapability<&{FungibleToken.Receiver}>(/public/dapperUtilityCoinReceiver)
192 assert(merchantDUCReceiverRef.borrow() != nil, message: "Missing or mis-typed merchant DUC receiver")
193
194 // Deposit DUC to Collector merchant account DUC Vault (it's then forwarded to the main DUC contract afterwards)
195 merchantDUCReceiverRef.borrow()!.deposit(from: <-paymentVault)
196
197 // Get buyer collection public to receive Collector
198 let recipient = getAccount(buyer)
199 let NFTReceiver = recipient.getCapability(Collector.CollectionPublicPath)
200 .borrow<&{NonFungibleToken.CollectionPublic}>()
201 ?? panic("Could not get receiver reference to the NFT Collection")
202
203 // Mint Collector NFTs per purchaseAmount
204 var mintCounter = numberOfTokens
205 while(mintCounter > 0) {
206 admin.mintNFT(recipient: NFTReceiver, setID: setID)
207 mintCounter = mintCounter - 1
208 }
209
210 // Remove utilized spots
211 self.publicSaleAccounts[buyer] = self.publicSaleAccounts[buyer]! - numberOfTokens
212 }
213
214 pub resource Admin {
215 //
216 // PRIVATE SALE FUNCTIONS
217 //
218 pub fun addAccountToPrivateSale(address: Address, amount: UInt64) {
219 pre {
220 amount <= CollectorMinter.privateSaleMaxTokens:
221 "Unable to allocate more private sale spots"
222 CollectorMinter.privateSaleAccounts[address] == nil:
223 "Provided address already added to the private sale"
224 }
225 CollectorMinter.privateSaleAccounts[address] = amount
226 }
227
228 pub fun removeAccountFromPrivateSale(address: Address) {
229 pre {
230 CollectorMinter.privateSaleAccounts[address] != nil:
231 "Provided address is not in the private sale list"
232 }
233 CollectorMinter.privateSaleAccounts.remove(key: address)
234 }
235
236 pub fun updatePrivateSaleAccountAmount(address: Address, amount: UInt64) {
237 pre {
238 CollectorMinter.privateSaleAccounts[address] != nil:
239 "Provided address is not in the private sale list"
240 }
241 CollectorMinter.privateSaleAccounts[address] = amount
242 }
243
244 pub fun updatePrivateSaleMaxTokens(amount: UInt64) {
245 CollectorMinter.privateSaleMaxTokens = amount
246 }
247
248 pub fun updatePrivateSalePrice(price: UFix64) {
249 CollectorMinter.privateSalePrice = price
250 }
251
252 pub fun prunePrivateSaleAccounts() {
253 CollectorMinter.privateSaleAccounts = {}
254 }
255
256 pub fun closePrivateSaleRegistration() {
257 CollectorMinter.privateSaleRegistrationOpen = false
258 }
259
260 pub fun openPrivateSaleRegistration() {
261 CollectorMinter.privateSaleRegistrationOpen = true
262 }
263
264 //
265 // PRESALE FUNCTIONS
266 //
267 pub fun addAccountToPresale(address: Address, amount: UInt64) {
268 pre {
269 amount <= CollectorMinter.presaleMaxTokens:
270 "Unable to allocate more presale spots"
271 CollectorMinter.presaleAccounts[address] == nil:
272 "Provided address already added to the presale"
273 }
274 CollectorMinter.presaleAccounts[address] = amount
275 }
276
277 pub fun removeAccountFromPresale(address: Address) {
278 pre {
279 CollectorMinter.presaleAccounts[address] != nil:
280 "Provided address is not in the presale list"
281 }
282 CollectorMinter.presaleAccounts.remove(key: address)
283 }
284
285 pub fun updatePresaleAccountAmount(address: Address, amount: UInt64) {
286 pre {
287 CollectorMinter.presaleAccounts[address] != nil:
288 "Provided address is not in the presale list"
289 }
290 CollectorMinter.presaleAccounts[address] = amount
291 }
292
293 pub fun updatePresaleMaxTokens(amount: UInt64) {
294 CollectorMinter.presaleMaxTokens = amount
295 }
296
297 pub fun updatePresalePrice(price: UFix64) {
298 CollectorMinter.presalePrice = price
299 }
300
301 pub fun prunePresaleAccounts() {
302 CollectorMinter.presaleAccounts = {}
303 }
304
305 pub fun closePresaleRegistration() {
306 CollectorMinter.presaleRegistrationOpen = false
307 }
308
309 pub fun openPresaleRegistration() {
310 CollectorMinter.presaleRegistrationOpen = true
311 }
312
313 //
314 // PUBLIC SALE FUNCTIONS
315 //
316 pub fun updatePublicSaleMaxTokens(amount: UInt64) {
317 CollectorMinter.publicSaleMaxTokens = amount
318 }
319
320 pub fun updatePublicSalePrice(price: UFix64) {
321 CollectorMinter.publicSalePrice = price
322 }
323
324 pub fun prunePublicSaleAccounts() {
325 CollectorMinter.publicSaleAccounts = {}
326 }
327
328 //
329 // COMMON
330 //
331 pub fun updateMerchantAccount(newAddr: Address) {
332 CollectorMinter.merchantAccount = newAddr
333 }
334 }
335
336 pub fun getPrivateSaleAccounts(): {Address: UInt64} {
337 return self.privateSaleAccounts
338 }
339
340 pub fun getPresaleAccounts(): {Address: UInt64} {
341 return self.presaleAccounts
342 }
343
344 pub fun getPublicSaleAccounts(): {Address: UInt64} {
345 return self.publicSaleAccounts
346 }
347
348 init(merchantAccount: Address) {
349 self.AdminStoragePath = /storage/CollectorMinterAdmin
350
351 self.privateSaleRegistrationOpen = true
352 self.presaleRegistrationOpen = true
353
354 self.privateSaleMaxTokens = 1
355 self.privateSalePrice = 10.00
356 self.privateSaleAccounts = {}
357
358 self.presaleMaxTokens = 3
359 self.presalePrice = 129.00
360 self.presaleAccounts = {}
361
362 self.publicSaleMaxTokens = 3
363 self.publicSalePrice = 179.00
364 self.publicSaleAccounts = {}
365
366 // For testnet this should be 0x03df89ac89a3d64a
367 // For mainnet this should be 0xfe15c4f52a58c75e
368 self.merchantAccount = merchantAccount
369
370 let admin <- create Admin()
371 self.account.save(<-admin, to: self.AdminStoragePath)
372
373 emit ContractInitialized(merchantAccount: merchantAccount)
374 }
375}
376