Smart Contract
FindForge
A.097bafa4e0b48eef.FindForge
1import FungibleToken from 0xf233dcee88fe0abe
2import NonFungibleToken from 0x1d7e57aa55817448
3import MetadataViews from 0x1d7e57aa55817448
4import FIND from 0x097bafa4e0b48eef
5import FindForgeOrder from 0x097bafa4e0b48eef
6import Profile from 0x097bafa4e0b48eef
7import ViewResolver from 0x1d7e57aa55817448
8
9
10access(all) contract FindForge {
11
12 access(all) event Minted(nftType: String, id: UInt64, uuid: UInt64, nftName: String, nftThumbnail: String, from: Address, fromName: String, to: Address, toName: String?)
13
14 access(contract) let minterPlatforms : {Type : {String: MinterPlatform}}
15 access(contract) let verifier : @Verifier
16
17 access(contract) let forgeTypes : @{Type : {Forge}}
18 access(contract) let publicForges : [Type]
19 access(contract) var platformCut: UFix64
20
21 access(all) struct MinterPlatform {
22 access(all) let platform: Capability<&{FungibleToken.Receiver}>
23 access(all) let platformPercentCut: UFix64
24 access(all) let name: String
25 access(all) let minter: Address
26
27 access(all) var description: String
28 access(all) var externalURL: String
29 access(all) var squareImage: String
30 access(all) var bannerImage: String
31 access(all) let minterCut: UFix64?
32 access(all) var socials: {String : String}
33
34 init(name: String, platform:Capability<&{FungibleToken.Receiver}>, platformPercentCut: UFix64, minterCut: UFix64? ,description: String, externalURL: String, squareImage: String, bannerImage: String, socials: {String : String}) {
35 self.name=name
36 self.minter=FIND.lookupAddress(self.name)!
37 self.platform=platform
38 self.platformPercentCut=platformPercentCut
39 self.description=description
40 self.externalURL=externalURL
41 self.squareImage=squareImage
42 self.bannerImage=bannerImage
43 self.minterCut=minterCut
44 self.socials=socials
45 }
46
47 access(all) fun getMinterFTReceiver() : Capability<&{FungibleToken.Receiver}> {
48 return getAccount(self.minter).capabilities.get<&{FungibleToken.Receiver}>(Profile.publicReceiverPath)!
49 }
50
51 access(all) fun updateExternalURL(_ d: String) {
52 self.externalURL = d
53 }
54
55 access(all) fun updateDesription(_ d: String) {
56 self.description = d
57 }
58
59 access(all) fun updateSquareImagen(_ d: String) {
60 self.squareImage = d
61 }
62
63 access(all) fun updateBannerImage(_ d: String) {
64 self.bannerImage = d
65 }
66
67 access(all) fun updateSocials(_ d: {String : String}) {
68 self.socials = d
69 }
70
71 }
72
73 // This is an empty resource that is created and passed into mint methods to verify that it comes from .find
74 access(all) resource Verifier {
75 }
76
77 // ForgeMinter Interface
78 access(all) resource interface Forge{
79 access(ForgeOwner) fun mint(platform: MinterPlatform, data: AnyStruct, verifier: &Verifier) : @{NonFungibleToken.NFT}
80 access(ForgeOwner) fun addContractData(platform: MinterPlatform, data: AnyStruct, verifier: &Verifier)
81 }
82
83 access(contract) fun borrowForge(_ type: Type) : auth(ForgeOwner) &{Forge}? {
84 return &FindForge.forgeTypes[type]
85 }
86
87 access(all) fun getMinterPlatform(name: String, forgeType: Type) : MinterPlatform? {
88 if FindForge.minterPlatforms[forgeType] == nil {
89 return nil
90 }
91 return FindForge.minterPlatforms[forgeType]![name]
92 }
93
94 access(all) fun getMinterPlatformsByName() : {Type : {String : MinterPlatform}} {
95 return FindForge.minterPlatforms
96 }
97
98 access(all) fun checkMinterPlatform(name: String, forgeType: Type) : Bool {
99 if FindForge.minterPlatforms[forgeType] == nil {
100 return false
101 }
102 if FindForge.minterPlatforms[forgeType]![name] == nil {
103 return false
104 } else if FindForge.minterPlatforms[forgeType]![name]!.description == "" {
105 return false
106 }
107 return true
108 }
109
110 access(all) fun setMinterPlatform(lease: &FIND.Lease, forgeType: Type, minterCut: UFix64?, description: String, externalURL: String, squareImage: String, bannerImage: String, socials: {String : String}) {
111 if !FindForge.minterPlatforms.containsKey(forgeType) {
112 panic("This forge type is not supported. type : ".concat(forgeType.identifier))
113 }
114
115 if description == "" {
116 panic("Description of collection cannot be empty")
117 }
118
119 let name = lease.getName()
120 if FindForge.minterPlatforms[forgeType]![name] == nil {
121 if !FindForge.publicForges.contains(forgeType) {
122 panic("This forge is not supported publicly. Forge Type : ".concat(forgeType.identifier))
123 }
124 }
125
126 // If they have a premium forge, platform will not take any royalty
127 if lease.checkAddon(addon: "premiumForge") {
128 let receiverCap=FindForge.account.capabilities.get<&{FungibleToken.Receiver}>(Profile.publicReceiverPath)!
129 let minterPlatform = MinterPlatform(name:name, platform:receiverCap, platformPercentCut: 0.0, minterCut: minterCut ,description: description, externalURL: externalURL, squareImage: squareImage, bannerImage: bannerImage, socials: socials)
130
131 FindForge.minterPlatforms[forgeType]!.insert(key: name, minterPlatform)
132 return
133 }
134
135 if lease.checkAddon(addon: "forge") {
136 let receiverCap=FindForge.account.capabilities.get<&{FungibleToken.Receiver}>(Profile.publicReceiverPath)!
137 let minterPlatform = MinterPlatform(name:name, platform:receiverCap, platformPercentCut: FindForge.platformCut, minterCut: minterCut ,description: description, externalURL: externalURL, squareImage: squareImage, bannerImage: bannerImage, socials: socials)
138
139 FindForge.minterPlatforms[forgeType]!.insert(key: name, minterPlatform)
140 return
141 }
142
143 panic("Please purchase forge addon to start forging. Name: ".concat(lease.getName()))
144 }
145
146 access(account) fun adminSetMinterPlatform(leaseName: String, forgeType: Type, minterCut: UFix64?, description: String, externalURL: String, squareImage: String, bannerImage: String, socials: {String : String}) {
147 if !FindForge.minterPlatforms.containsKey(forgeType) {
148 FindForge.addPrivateForgeType(name: leaseName, forgeType: forgeType)
149 }
150
151 if description == "" {
152 panic("Description of collection cannot be empty")
153 }
154
155 let user = FIND.lookupAddress(leaseName) ?? panic("Cannot find lease owner. Lease : ".concat(leaseName))
156 let leaseCollection = getAccount(user).capabilities.get<&{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath)!.borrow() ?? panic("Cannot borrow reference to lease collection of user : ".concat(leaseName))
157
158 // If they have a premium forge, platform will not take any royalty
159 if leaseCollection.checkAddon(name: leaseName, addon: "premiumForge") {
160 let receiverCap=FindForge.account.capabilities.get<&{FungibleToken.Receiver}>(Profile.publicReceiverPath)!
161 let minterPlatform = MinterPlatform(name:leaseName, platform:receiverCap, platformPercentCut: 0.0, minterCut: minterCut ,description: description, externalURL: externalURL, squareImage: squareImage, bannerImage: bannerImage, socials: socials)
162
163 FindForge.minterPlatforms[forgeType]!.insert(key: leaseName, minterPlatform)
164 return
165 }
166
167 if leaseCollection.checkAddon(name: leaseName, addon: "forge") {
168 let receiverCap=FindForge.account.capabilities.get<&{FungibleToken.Receiver}>(Profile.publicReceiverPath)!
169 let minterPlatform = MinterPlatform(name:leaseName, platform:receiverCap, platformPercentCut: FindForge.platformCut, minterCut: minterCut ,description: description, externalURL: externalURL, squareImage: squareImage, bannerImage: bannerImage, socials: socials)
170
171 FindForge.minterPlatforms[forgeType]!.insert(key: leaseName, minterPlatform)
172 return
173 }
174
175 panic("Please give the user forge addon to start forging. Name: ".concat(leaseName))
176 }
177
178 access(all) fun removeMinterPlatform(lease: &FIND.Lease, forgeType: Type) {
179 if FindForge.minterPlatforms[forgeType] == nil {
180 panic("This minter platform does not exist. Forge Type : ".concat(forgeType.identifier))
181 }
182 let name = lease.getName()
183
184 if FindForge.minterPlatforms[forgeType]![name] == nil {
185 panic("This user does not have corresponding minter platform under this forge. Forge Type : ".concat(forgeType.identifier))
186 }
187
188 FindForge.minterPlatforms[forgeType]!.remove(key: name)
189 }
190
191 access(account) fun mintAdmin(leaseName: String, forgeType: Type , data: AnyStruct, receiver: &{NonFungibleToken.Receiver}) {
192 if !FindForge.minterPlatforms.containsKey(forgeType) {
193 panic("The minter platform is not set. Please set up properly before mint.")
194 }
195
196 let minterPlatform = FindForge.minterPlatforms[forgeType]![leaseName] ?? panic("The minter platform is not set. Please set up properly before mint.")
197
198 if minterPlatform.description == "" {
199 panic("Please set up minter platform before mint")
200 }
201
202 let verifier = self.borrowVerifier()
203
204 let forge = FindForge.borrowForge(forgeType) ?? panic("The forge type passed in is not supported. Forge Type : ".concat(forgeType.identifier))
205
206 let nft <- forge.mint(platform: minterPlatform, data: data, verifier: verifier)
207
208 let id = nft.id
209 let uuid = nft.uuid
210 let nftType = nft.getType().identifier
211 receiver.deposit(token: <- nft)
212
213 /*
214 let vr = receiver.borrowNFT(id)
215 let view = vr.resolveView(Type<MetadataViews.Display>()) ?? panic("The minting nft should implement MetadataViews Display view.")
216 let display = view as! MetadataViews.Display
217 let nftName = display.name
218 let thumbnail = display.thumbnail.uri()
219 let to = receiver.owner!.address
220 let toName = FIND.reverseLookup(to)
221 let new = FIND.reverseLookup(to)
222 let from = FindForge.account.address
223
224 emit Minted(nftType: nftType, id: id, uuid: uuid, nftName: nftName, nftThumbnail: thumbnail, from: from, fromName: leaseName, to: to, toName: toName)
225 */
226
227 }
228
229 access(all) fun orderForge(lease: &FIND.Lease, mintType: String, minterCut: UFix64?, collectionDisplay: MetadataViews.NFTCollectionDisplay){
230 if !lease.checkAddon(addon: "forge") && !lease.checkAddon(addon: "premiumForge") {
231 panic("Please purchase forge addon to start forging. Name: ".concat(lease.getName()))
232 }
233
234 FindForgeOrder.orderForge(leaseName: lease.getName(), mintType: mintType, minterCut: minterCut, collectionDisplay: collectionDisplay)
235 }
236
237 access(account) fun adminOrderForge(leaseName: String, mintType: String, minterCut: UFix64?, collectionDisplay: MetadataViews.NFTCollectionDisplay){
238 FindForgeOrder.orderForge(leaseName: leaseName, mintType: mintType, minterCut: minterCut, collectionDisplay: collectionDisplay)
239 }
240
241 access(account) fun cancelForgeOrder(leaseName: String, mintType: String) {
242 FindForgeOrder.cancelForgeOrder(leaseName: leaseName, mintType: mintType)
243 }
244
245 access(account) fun fulfillForgeOrder(_ contractName: String, forgeType: Type) : MetadataViews.NFTCollectionDisplay {
246 let order = FindForgeOrder.fulfillForgeOrder(contractName, forgeType: forgeType)
247 let c = order.getCollectionDisplay()
248 let s : {String : String} = {}
249 for social in c.socials.keys {
250 s[social] = c.socials[social]!.url
251 }
252 FindForge.adminSetMinterPlatform(leaseName: order.getLeaseName(),
253 forgeType: forgeType,
254 minterCut: order.getMinterCut(),
255 description: c.description,
256 externalURL: c.externalURL.url,
257 squareImage: c.squareImage.file.uri(),
258 bannerImage: c.bannerImage.file.uri(),
259 socials: s)
260 return c
261 }
262
263 access(all) fun mint (lease: &FIND.Lease, forgeType: Type , data: AnyStruct, receiver: &{NonFungibleToken.Receiver, ViewResolver.ResolverCollection}) {
264 let leaseName = lease.getName()
265 FindForge.adminMint(lease: leaseName, forgeType: forgeType , data: data, receiver: receiver)
266 }
267
268 access(account) fun adminMint(lease: String, forgeType: Type , data: AnyStruct, receiver: &{NonFungibleToken.Receiver, ViewResolver.ResolverCollection}){
269 if !FindForge.minterPlatforms.containsKey(forgeType) {
270 panic("The minter platform is not set. Please set up properly before adding contract data.")
271 }
272 let address = FIND.lookupAddress(lease) ?? panic("This name is not owned by anyone. Name : ".concat(lease))
273 let leaseCol = getAccount(address).capabilities.get<&{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath)!.borrow() ?? panic("Cannot borrow lease collection to lease owner. Owner : ".concat(address.toString()))
274
275 if !leaseCol.checkAddon(name:lease, addon: "forge") && !leaseCol.checkAddon(name:lease, addon: "premiumForge") {
276 panic("Please purchase forge addon to start forging. Name: ".concat(lease))
277 }
278
279 let minterPlatform = FindForge.minterPlatforms[forgeType]![lease] ?? panic("The minter platform is not set. Please set up properly before mint.")
280
281 if minterPlatform.description == "" {
282 panic("Please set up minter platform before mint")
283 }
284
285 let verifier = self.borrowVerifier()
286
287 let forge = FindForge.borrowForge(forgeType) ?? panic("The forge type passed in is not supported. Forge Type : ".concat(forgeType.identifier))
288
289 let nft <- forge.mint(platform: minterPlatform, data: data, verifier: verifier)
290
291 let id = nft.id
292 let uuid = nft.uuid
293 let nftType = nft.getType().identifier
294 receiver.deposit(token: <- nft)
295
296 let vr = (receiver as &{ViewResolver.ResolverCollection}).borrowViewResolver(id: id)!
297 let view = vr.resolveView(Type<MetadataViews.Display>()) ?? panic("The minting nft should implement MetadataViews Display view.")
298 let display = view as! MetadataViews.Display
299 let nftName = display.name
300 let thumbnail = display.thumbnail.uri()
301 let to = receiver.owner!.address
302 let toName = FIND.reverseLookup(to)
303 let new = FIND.reverseLookup(to)
304 let from = FindForge.account.address
305
306 emit Minted(nftType: nftType, id: id, uuid: uuid, nftName: nftName, nftThumbnail: thumbnail, from: from, fromName: "find", to: to, toName: toName)
307
308 }
309
310 access(all) fun addContractData(lease: &FIND.Lease, forgeType: Type , data: AnyStruct) {
311 FindForge.adminAddContractData(lease: lease.getName(), forgeType: forgeType , data: data)
312 }
313
314 access(account) fun adminAddContractData(lease: String, forgeType: Type , data: AnyStruct) {
315
316 if !FindForge.minterPlatforms.containsKey(forgeType) {
317 panic("The minter platform is not set. Please set up properly before adding contract data.")
318 }
319 let address = FIND.lookupAddress(lease) ?? panic("This name is not owned by anyone. Name : ".concat(lease))
320 let leaseCol = getAccount(address).capabilities.get<&{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath)!.borrow() ?? panic("Cannot borrow lease collection to lease owner. Owner : ".concat(address.toString()))
321
322 if !leaseCol.checkAddon(name:lease, addon: "forge") && !leaseCol.checkAddon(name:lease, addon: "premiumForge") {
323 panic("Please purchase forge addon to start forging. Name: ".concat(lease))
324 }
325
326 let minterPlatform = FindForge.minterPlatforms[forgeType]![lease] ?? panic("The minter platform is not set. Please set up properly.")
327
328 if minterPlatform.description == "" {
329 panic("Please set up minter platform")
330 }
331
332 let verifier = self.borrowVerifier()
333
334 let forge = FindForge.borrowForge(forgeType) ?? panic("The forge type passed in is not supported. Forge Type : ".concat(forgeType.identifier))
335 forge.addContractData(platform: minterPlatform, data: data, verifier: verifier)
336 }
337
338 access(all) fun addForgeType(_ forge: @{Forge}) {
339 if FindForge.forgeTypes.containsKey(forge.getType()) {
340 panic("This type is already registered to the registry. Type : ".concat(forge.getType().identifier))
341 }
342
343 FindForge.forgeTypes[forge.getType()] <-! forge
344 }
345
346 access(account) fun addPublicForgeType(forgeType: Type) {
347 if !FindForge.forgeTypes.containsKey(forgeType) {
348 panic("This type is not registered to the registry. Type : ".concat(forgeType.identifier))
349 }
350 if FindForge.publicForges.contains(forgeType) {
351 panic("This type is already registered as public forge. Type : ".concat(forgeType.identifier))
352 }
353 FindForge.publicForges.append(forgeType)
354 if !FindForge.minterPlatforms.containsKey(forgeType) {
355 FindForge.minterPlatforms[forgeType] = {}
356 }
357 }
358
359 access(account) fun addPrivateForgeType(name: String, forgeType: Type) {
360 if !FindForge.forgeTypes.containsKey(forgeType) {
361 panic("This type is not registered to the registry. Type : ".concat(forgeType.identifier))
362 }
363
364 if !FindForge.minterPlatforms.containsKey(forgeType) {
365 FindForge.minterPlatforms[forgeType] = {}
366 }
367 let receiverCap=FindForge.account.capabilities.get<&{FungibleToken.Receiver}>(Profile.publicReceiverPath)!
368 let minterPlatform = MinterPlatform(name:name, platform:receiverCap, platformPercentCut: FindForge.platformCut, minterCut: nil ,description: "", externalURL: "", squareImage: "", bannerImage: "", socials: {})
369 FindForge.minterPlatforms[forgeType]!.insert(key: name, minterPlatform)
370 }
371
372 access(account) fun adminRemoveMinterPlatform(name: String, forgeType: Type) {
373 if !FindForge.minterPlatforms.containsKey(forgeType) {
374 panic("This type is not registered as minterPlatform. Type : ".concat(forgeType.identifier))
375 }
376 if !FindForge.minterPlatforms[forgeType]!.containsKey(name) {
377 panic("This name is not registered as minterPlatform under this input type. ".concat(name))
378 }
379 FindForge.minterPlatforms[forgeType]!.remove(key: name)
380 }
381
382 access(account) fun removeForgeType(type: Type) {
383 if !FindForge.forgeTypes.containsKey(type) {
384 panic( "This type is not registered to the registry. Type : ".concat(type.identifier))
385 }
386
387 var i = 0
388 for forge in FindForge.publicForges {
389 if forge == type {
390 FindForge.publicForges.remove(at: i)
391 break
392 }
393 i = i + 1
394 }
395 FindForge.minterPlatforms.remove(key: type)
396
397 }
398
399 access(account) fun setPlatformCut(_ cut: UFix64) {
400 FindForge.platformCut = cut
401 }
402
403 access(account) fun borrowVerifier() : &Verifier {
404 return &self.verifier
405 }
406
407 access(all) fun createForgeAdminProxyClient() : @ForgeAdminProxy {
408 return <- create ForgeAdminProxy()
409 }
410
411 //interface to use for capability receiver pattern
412 access(all) resource interface ForgeAdminProxyClient {
413 access(all) fun addCapability(_ cap: Capability<&FIND.Network>)
414 }
415
416 access(all) entitlement ForgeOwner
417
418 //admin proxy with capability receiver
419 access(all) resource ForgeAdminProxy: ForgeAdminProxyClient {
420
421 access(self) var capability: Capability<&FIND.Network>?
422
423 init() {
424 self.capability = nil
425 }
426
427 access(all) fun addCapability(_ cap: Capability<&FIND.Network>) {
428 pre {
429 cap.check() : "Invalid server capablity"
430 self.capability == nil : "Server already set"
431 }
432 self.capability = cap
433 }
434
435 access(ForgeOwner) fun fulfillForgeOrder(_ contractName: String, forgeType: Type) : MetadataViews.NFTCollectionDisplay {
436 pre {
437 self.capability != nil: "Cannot create FIND, capability is not set"
438 }
439 return FindForge.fulfillForgeOrder(contractName, forgeType: forgeType)
440 }
441 }
442
443 init() {
444 self.minterPlatforms={}
445 self.publicForges=[]
446 self.forgeTypes<-{}
447 self.platformCut=0.025
448
449 self.verifier <- create Verifier()
450 }
451
452}
453