Smart Contract

FindForge

A.097bafa4e0b48eef.FindForge

Deployed

2d ago
Feb 26, 2026, 03:12:51 AM UTC

Dependents

0 imports
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