Smart Contract

FindLeaseMarket

A.097bafa4e0b48eef.FindLeaseMarket

Deployed

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

Dependents

23 imports
1import FungibleToken from 0xf233dcee88fe0abe
2import FindViews from 0x097bafa4e0b48eef
3import FIND from 0x097bafa4e0b48eef
4import Profile from 0x097bafa4e0b48eef
5import Clock from 0x097bafa4e0b48eef
6import FTRegistry from 0x097bafa4e0b48eef
7import MetadataViews from 0x1d7e57aa55817448
8import FindMarket from 0x097bafa4e0b48eef
9import FindRulesCache from 0x097bafa4e0b48eef
10import FindMarketCutStruct from 0x097bafa4e0b48eef
11import FindUtils from 0x097bafa4e0b48eef
12
13access(all) contract FindLeaseMarket {
14
15    access(contract) let  saleItemTypes : [Type]
16    access(contract) let  saleItemCollectionTypes : [Type]
17    access(contract) let  marketBidTypes : [Type]
18    access(contract) let  marketBidCollectionTypes : [Type]
19
20    access(all) event RoyaltyPaid(tenant:String, leaseName: String, saleID: UInt64, address:Address, findName:String?, royaltyName:String, amount: UFix64, vaultType:String, leaseInfo:LeaseInfo)
21    access(all) event RoyaltyCouldNotBePaid(tenant:String, leaseName: String, saleID: UInt64, address:Address, findName:String?, royaltyName:String, amount: UFix64, vaultType:String, leaseInfo:LeaseInfo, residualAddress: Address)
22    access(all) event FindBlockRules(tenant: String, ruleName: String, ftTypes:[String], listingTypes:[String], status:String)
23    access(all) event TenantAllowRules(tenant: String, ruleName: String, ftTypes:[String], listingTypes:[String], status:String)
24    access(all) event FindCutRules(tenant: String, ruleName: String, cut:UFix64, ftTypes:[String], listingTypes:[String], status:String)
25
26    // ========================================
27
28    /* Get Tenant */
29    access(all) fun getTenant(_ tenant: Address) : &{FindMarket.TenantPublic} {
30        return FindMarket.getTenantCapability(tenant)!.borrow()!
31    }
32
33    access(all) fun getSaleItemTypes() : [Type] {
34        return self.saleItemTypes
35    }
36
37    /* Get SaleItemCollections */
38    access(all) fun getSaleItemCollectionTypes() : [Type] {
39        return self.saleItemCollectionTypes
40    }
41
42    access(all) fun getSaleItemCollectionCapabilities(tenantRef: &{FindMarket.TenantPublic}, address: Address) : [Capability<&{FindLeaseMarket.SaleItemCollectionPublic}>] {
43        var caps : [Capability<&{FindLeaseMarket.SaleItemCollectionPublic}>] = []
44        for type in self.getSaleItemCollectionTypes() {
45            if type != nil {
46                let cap = getAccount(address).capabilities.get<&{FindLeaseMarket.SaleItemCollectionPublic}>(tenantRef.getPublicPath(type)) 
47                if cap.check() {
48                    caps.append(cap)
49                }
50            }
51        }
52        return caps
53    }
54
55    access(all) fun getSaleItemCollectionCapability(tenantRef: &{FindMarket.TenantPublic}, marketOption: String, address: Address) : Capability<&{FindLeaseMarket.SaleItemCollectionPublic}>? {
56        for type in self.getSaleItemCollectionTypes() {
57            if FindMarket.getMarketOptionFromType(type) == marketOption{
58                let path=tenantRef.getPublicPath(type)
59                let cap = getAccount(address).capabilities.get<&{FindLeaseMarket.SaleItemCollectionPublic}>(path)
60                return cap
61            }
62        }
63        panic("Cannot find market option : ".concat(marketOption))
64    }
65
66    /* Get Sale Reports and Sale Item */
67    access(all) fun assertOperationValid(tenant: Address, name: String, marketOption: String) : &{SaleItem} {
68        let tenantRef=self.getTenant(tenant)
69        let address=FIND.lookupAddress(name) ?? panic("Name is not owned by anyone. Name : ".concat(name))
70        let collectionCap = self.getSaleItemCollectionCapability(tenantRef: tenantRef, marketOption: marketOption, address: address)
71        let optRef = collectionCap?.borrow()
72        if optRef == nil {
73            panic("Account not properly set up, cannot borrow sale item collection")
74        }
75        let ref=optRef!!
76        let item=ref.borrowSaleItem(name)
77        if !item.checkPointer() {
78            panic("this is a ghost listing")
79        }
80
81        return item
82    }
83
84    /* Get Sale Reports and Sale Item */
85    access(all) fun getSaleInformation(tenant: Address, name: String, marketOption: String, getLeaseInfo: Bool) : FindLeaseMarket.SaleItemInformation? {
86        let address = FIND.lookupAddress(name) ?? panic("Name is not owned by anyone. Name : ".concat(name))
87        let tenantRef=self.getTenant(tenant)
88        let info = self.checkSaleInformation(tenantRef: tenantRef, marketOption:marketOption, address: address, name: name, getGhost: false, getLeaseInfo: getLeaseInfo)
89        if info.items.length > 0 {
90            return info.items[0]
91        }
92        return nil
93    }
94
95    access(all) fun getSaleItemReport(tenant:Address, address: Address, getLeaseInfo: Bool) : {String : FindLeaseMarket.SaleItemCollectionReport} {
96        let tenantRef = self.getTenant(tenant)
97        var report : {String : FindLeaseMarket.SaleItemCollectionReport} = {}
98        for type in self.getSaleItemCollectionTypes() {
99            let marketOption = FindMarket.getMarketOptionFromType(type)
100            let returnedReport = self.checkSaleInformation(tenantRef: tenantRef, marketOption:marketOption, address: address, name: nil, getGhost: true, getLeaseInfo: getLeaseInfo)
101            if returnedReport.items.length > 0 || returnedReport.ghosts.length > 0 {
102                report[marketOption] = returnedReport
103            }
104        }
105        return report
106    }
107
108    access(all) fun getSaleItems(tenant:Address, name: String, getLeaseInfo: Bool) : {String : FindLeaseMarket.SaleItemCollectionReport} {
109        let address = FIND.lookupAddress(name) ?? panic("Name is not owned by anyone. Name : ".concat(name))
110        let tenantRef = self.getTenant(tenant)
111        var report : {String : FindLeaseMarket.SaleItemCollectionReport} = {}
112        for type in self.getSaleItemCollectionTypes() {
113            let marketOption = FindMarket.getMarketOptionFromType(type)
114            let returnedReport = self.checkSaleInformation(tenantRef: tenantRef, marketOption:marketOption, address: address, name: name, getGhost: true, getLeaseInfo: getLeaseInfo)
115            if returnedReport.items.length > 0 || returnedReport.ghosts.length > 0 {
116                report[marketOption] = returnedReport
117            }
118        }
119        return report
120    }
121
122    access(all) fun getLeaseListing(tenant:Address, name: String, getLeaseInfo: Bool) : {String : FindLeaseMarket.SaleItemInformation} {
123        let address = FIND.lookupAddress(name) ?? panic("Name is not owned by anyone. Name : ".concat(name))
124        let tenantRef = self.getTenant(tenant)
125        var report : {String : FindLeaseMarket.SaleItemInformation} = {}
126        for type in self.getSaleItemCollectionTypes() {
127            let marketOption = FindMarket.getMarketOptionFromType(type)
128            let returnedReport = self.checkSaleInformation(tenantRef: tenantRef, marketOption:marketOption, address: address, name: name, getGhost: true, getLeaseInfo: getLeaseInfo)
129            if returnedReport.items.length > 0 || returnedReport.ghosts.length > 0 {
130                report[marketOption] = returnedReport.items[0]
131            }
132        }
133        return report
134    }
135
136    access(contract) fun checkSaleInformation(tenantRef: &{FindMarket.TenantPublic}, marketOption: String, address: Address, name: String?, getGhost: Bool, getLeaseInfo: Bool) : FindLeaseMarket.SaleItemCollectionReport {
137        let ghost: [FindLeaseMarket.GhostListing] =[]
138        let info: [FindLeaseMarket.SaleItemInformation] =[]
139        let collectionCap = self.getSaleItemCollectionCapability(tenantRef: tenantRef, marketOption: marketOption, address: address)
140        let optRef = collectionCap?.borrow()
141        if optRef == nil {
142            return FindLeaseMarket.SaleItemCollectionReport(items: info, ghosts: ghost)
143        }
144        let ref=optRef!!
145
146        var listName : [String]= []
147        if let leaseName = name{
148            if !ref.containsNameSale(leaseName) {
149                return FindLeaseMarket.SaleItemCollectionReport(items: info, ghosts: ghost)
150            }
151            listName=[leaseName]
152        } else {
153            listName = ref.getNameSales()
154        }
155
156        let listingType = ref.getListingType()
157
158        for leaseName in listName {
159            //if this id is not present in this Market option then we just skip it
160            let item=ref.borrowSaleItem(leaseName)
161            if !item.checkPointer() {
162                if getGhost {
163                    ghost.append(FindLeaseMarket.GhostListing(listingType: listingType, name:leaseName))
164                }
165                continue
166            }
167            let stopped=tenantRef.allowedAction(listingType: listingType, nftType: item.getItemType(), ftType: item.getFtType(), action: FindMarket.MarketAction(listing:false, name:"delist item for sale"), seller: address, buyer: nil)
168            var status="active"
169
170            if !stopped.allowed && stopped.message == "Seller banned by Tenant" {
171                status="banned"
172                info.append(FindLeaseMarket.SaleItemInformation(item: item, status: status, leaseInfo: false))
173                continue
174            }
175
176            if !stopped.allowed {
177                status="stopped"
178                info.append(FindLeaseMarket.SaleItemInformation(item: item, status: status, leaseInfo: false))
179                continue
180            }
181
182            let deprecated=tenantRef.allowedAction(listingType: listingType, nftType: item.getItemType(), ftType: item.getFtType(), action: FindMarket.MarketAction(listing:true, name:"delist item for sale"), seller: address, buyer: nil)
183
184            if !deprecated.allowed {
185                status="deprecated"
186                info.append(FindLeaseMarket.SaleItemInformation(item: item, status: status, leaseInfo: getLeaseInfo))
187                continue
188            }
189
190            if let validTime = item.getValidUntil() {
191                if validTime <= Clock.time() {
192                    status="ended"
193                }
194            }
195            info.append(FindLeaseMarket.SaleItemInformation(item: item, status: status, leaseInfo: getLeaseInfo))
196        }
197
198        return FindLeaseMarket.SaleItemCollectionReport(items: info, ghosts: ghost)
199    }
200
201    /* Get Bid Collections */
202    access(all) fun getMarketBidTypes() : [Type] {
203        return self.marketBidTypes
204    }
205
206    access(all) fun getMarketBidCollectionTypes() : [Type] {
207        return self.marketBidCollectionTypes
208    }
209
210    access(all) fun getMarketBidCollectionCapabilities(tenantRef: &{FindMarket.TenantPublic}, address: Address) : [Capability<&{FindLeaseMarket.MarketBidCollectionPublic}>] {
211        var caps : [Capability<&{FindLeaseMarket.MarketBidCollectionPublic}>] = []
212        for type in self.getMarketBidCollectionTypes() {
213            let cap = getAccount(address).capabilities.get<&{FindLeaseMarket.MarketBidCollectionPublic}>(tenantRef.getPublicPath(type))
214            if cap.check() {
215                caps.append(cap)
216            }
217        }
218        return caps
219    }
220
221    access(all) fun getMarketBidCollectionCapability(tenantRef: &{FindMarket.TenantPublic}, marketOption: String, address: Address) : Capability<&{FindLeaseMarket.MarketBidCollectionPublic}>? {
222        for type in self.getMarketBidCollectionTypes() {
223            if FindMarket.getMarketOptionFromType(type) == marketOption{
224                let cap = getAccount(address).capabilities.get<&{FindLeaseMarket.MarketBidCollectionPublic}>(tenantRef.getPublicPath(type))
225                return cap
226            }
227        }
228        panic("Cannot find market option : ".concat(marketOption))
229    }
230
231    access(all) fun getBid(tenant: Address, address: Address, marketOption: String, name:String, getLeaseInfo: Bool) : FindLeaseMarket.BidInfo? {
232        let tenantRef=self.getTenant(tenant)
233        let bidInfo = self.checkBidInformation(tenantRef: tenantRef, marketOption: marketOption, address: address, name: name, getGhost: false, getLeaseInfo: getLeaseInfo)
234        if bidInfo.items.length > 0 {
235            return bidInfo.items[0]
236        }
237        return nil
238    }
239
240    access(all) fun getBidsReport(tenant:Address, address: Address, getLeaseInfo: Bool) : {String : FindLeaseMarket.BidItemCollectionReport} {
241        let tenantRef = self.getTenant(tenant)
242        var report : {String : FindLeaseMarket.BidItemCollectionReport} = {}
243        for type in self.getMarketBidCollectionTypes() {
244            let marketOption = FindMarket.getMarketOptionFromType(type)
245            let returnedReport = self.checkBidInformation(tenantRef: tenantRef, marketOption: marketOption, address: address, name: nil, getGhost: true, getLeaseInfo: getLeaseInfo)
246            if returnedReport.items.length > 0 || returnedReport.ghosts.length > 0 {
247                report[marketOption] = returnedReport
248            }
249        }
250        return report
251    }
252
253    access(contract) fun checkBidInformation(tenantRef: &{FindMarket.TenantPublic}, marketOption: String, address: Address, name: String?, getGhost:Bool, getLeaseInfo: Bool) : FindLeaseMarket.BidItemCollectionReport {
254        let ghost: [FindLeaseMarket.GhostListing] =[]
255        let info: [FindLeaseMarket.BidInfo] =[]
256        let collectionCap = self.getMarketBidCollectionCapability(tenantRef: tenantRef, marketOption: marketOption, address: address)
257
258        let optRef = collectionCap?.borrow()
259        if optRef==nil {
260            return FindLeaseMarket.BidItemCollectionReport(items: info, ghosts: ghost)
261        }
262
263        let ref=optRef!!
264
265        let listingType = ref.getBidType()
266        var listName : [String]= []
267        if let leaseName = name{
268            if !ref.containsNameBid(leaseName) {
269                return FindLeaseMarket.BidItemCollectionReport(items: info, ghosts: ghost)
270            }
271            listName=[leaseName]
272        } else {
273            listName = ref.getNameBids()
274        }
275
276        for leaseName in listName {
277
278            let bid=ref.borrowBidItem(leaseName)
279            let item=self.getSaleInformation(tenant: tenantRef.owner!.address, name: leaseName, marketOption: marketOption, getLeaseInfo: getLeaseInfo)
280            if item == nil {
281                if getGhost {
282                    ghost.append(FindLeaseMarket.GhostListing(listingType: listingType, name:leaseName))
283                }
284                continue
285            }
286            let bidInfo = FindLeaseMarket.BidInfo(name: leaseName, bidTypeIdentifier: listingType.identifier,  bidAmount: bid.getBalance(), timestamp: Clock.time(), item:item!)
287            info.append(bidInfo)
288
289        }
290        return FindLeaseMarket.BidItemCollectionReport(items: info, ghosts: ghost)
291    }
292
293    access(all) fun assertBidOperationValid(tenant: Address, address: Address, marketOption: String, name:String) : &{SaleItem} {
294        let tenantRef=self.getTenant(tenant)
295        let collectionCap = self.getMarketBidCollectionCapability(tenantRef: tenantRef, marketOption: marketOption, address: address)
296        let optRef = collectionCap?.borrow()
297        if optRef == nil {
298            panic("Account not properly set up, cannot borrow bid item collection")
299        }
300        let ref=optRef!!
301        let bidItem=ref.borrowBidItem(name)
302
303        let saleItemCollectionCap = self.getSaleItemCollectionCapability(tenantRef: tenantRef, marketOption: marketOption, address: bidItem.getSellerAddress())
304        let saleRef = saleItemCollectionCap?.borrow()
305        if saleRef == nil {
306            panic("Seller account is not properly set up, cannot borrow sale item collection")
307        }
308        let sale=saleRef!!
309        let item=sale.borrowSaleItem(name)
310        if !item.checkPointer() {
311            panic("this is a ghost listing")
312        }
313
314        return item
315    }
316
317    /////// Pointer Section
318
319    access(all) struct interface LeasePointer {
320        access(all) let name: String
321        access(all) let uuid: UInt64
322        access(all) fun valid() : Bool
323        access(all) fun getUUID() :UInt64
324        access(all) fun getLease() : FIND.LeaseInformation
325        access(all) fun owner() : Address
326        access(contract) fun borrow() : &FIND.LeaseCollection
327    }
328
329    access(all) struct ReadLeasePointer : LeasePointer {
330        access(self) let cap: Capability<&FIND.LeaseCollection>
331        access(all) let name: String
332        access(all) let uuid: UInt64
333
334        // Passing in the reference here to ensure that is the owner
335        init(name: String) {
336            let address = FIND.lookupAddress(name) ?? panic("This lease name is not owned")
337            self.cap=getAccount(address).capabilities.get<&FIND.LeaseCollection>(FIND.LeasePublicPath)
338            self.name=name
339
340            if !self.cap.check() {
341                panic("The capability is not valid.")
342            }
343
344            self.uuid = self.cap.borrow()!.getLeaseUUID(name)
345        }
346
347        access(contract) fun borrow() : &FIND.LeaseCollection {
348            return self.cap.borrow() ?? panic("The capability of pointer is not linked.")
349        }
350
351        access(all) fun getLease() : FIND.LeaseInformation {
352            return self.borrow().getLease(self.name) ?? panic("The owner doesn't hold the lease anymore".concat(self.name))
353        }
354
355        access(all) fun getUUID() :UInt64{
356            return self.uuid
357        }
358
359        access(all) fun owner() : Address {
360            return self.cap.address
361        }
362
363        access(all) fun valid() : Bool {
364            if !self.cap.check() || !self.cap.borrow()!.getNames().contains(self.name) {
365                return false
366            }
367
368            if Clock.time() > FindLeaseMarket.getNetwork().getLeaseExpireTime(self.name) {
369                return false
370            }
371            return true
372        }
373    }
374
375    access(all) struct AuthLeasePointer : LeasePointer {
376        access(self) let cap: Capability<auth(FIND.LeaseOwner) &FIND.LeaseCollection>
377        access(all) let name: String
378        access(all) let uuid: UInt64
379
380        // Passing in the reference here to ensure that is the owner
381        init(cap:Capability<auth(FIND.LeaseOwner) &FIND.LeaseCollection>, name: String) {
382            self.cap=cap
383            self.name=name
384
385            if !self.cap.borrow()!.getNames().contains(name) {
386                panic("Please pass in the corresponding lease collection reference.")
387            }
388
389            if !self.cap.check() {
390                panic("The capability is not valid.")
391            }
392
393            self.uuid = self.cap.borrow()!.getLeaseUUID(name)
394        }
395
396        access(contract) fun borrow() : auth(FIND.LeaseOwner) &FIND.LeaseCollection {
397            return self.cap.borrow() ?? panic("The capability of pointer is not linked.")
398        }
399
400        access(all) fun getLease() : FIND.LeaseInformation {
401            return self.borrow().getLease(self.name) ?? panic("The owner doesn't hold the lease anymore".concat(self.name))
402        }
403
404        access(all) fun getUUID() :UInt64{
405            return self.uuid
406        }
407
408        access(all) fun valid() : Bool {
409            if !self.cap.check() || !self.cap.borrow()!.getNames().contains(self.name) {
410                return false
411            }
412
413            if Clock.time() > FindLeaseMarket.getNetwork().getLeaseExpireTime(self.name) {
414                return false
415            }
416            return true
417        }
418
419        access(account) fun move(to: Address) {
420            if !self.valid() {
421                panic("The lease capability is not valid")
422            }
423            let receiver = getAccount(to)
424            let profile = receiver.capabilities.get<&{Profile.Public}>(Profile.publicPath)
425            let leases = receiver.capabilities.get<&FIND.LeaseCollection>(FIND.LeasePublicPath)
426            self.borrow().move(name: self.name, profile: profile, to: leases)
427        }
428
429        access(all) fun owner() : Address {
430            return self.cap.address
431        }
432
433    }
434
435    access(account) fun pay(tenant: String, leaseName: String, saleItem: &{SaleItem}, vault: @{FungibleToken.Vault}, leaseInfo: LeaseInfo, cuts:{String : FindMarketCutStruct.Cuts}) {
436        let buyer=saleItem.getBuyer()
437        let seller=saleItem.getSeller()
438        let soldFor=vault.balance
439        let ftType=vault.getType()
440        let ftInfo = FTRegistry.getFTInfoByTypeIdentifier(ftType.identifier)! // If this panic, there is sth wrong in FT set up
441        let oldProfileCap= getAccount(seller).capabilities.get<&{FungibleToken.Receiver}>(Profile.publicReceiverPath)
442        let oldProfile = FindMarket.getPaymentWallet(oldProfileCap, ftInfo, panicOnFailCheck: true)
443
444        for key in cuts.keys {
445            let allCuts = cuts[key]!
446            for cut in allCuts.cuts {
447                if var cutAmount= cut.getAmountPayable(soldFor) {
448                    let findName = FIND.reverseLookup(cut.getAddress())
449                    emit RoyaltyPaid(tenant: tenant, leaseName: leaseName, saleID: saleItem.uuid, address:cut.getAddress(), findName: findName , royaltyName: cut.getName(), amount: cutAmount,  vaultType: ftType.identifier, leaseInfo:leaseInfo)
450                    let vaultRef = cut.getReceiverCap().borrow() ?? panic("Royalty receiving account is not set up properly. Royalty account address : ".concat(cut.getAddress().toString()).concat(" Royalty Name : ").concat(cut.getName()))
451                    vaultRef.deposit(from: <- vault.withdraw(amount: cutAmount))
452                }
453            }
454        }
455
456
457        oldProfile.deposit(from: <- vault)
458    }
459
460    //struct to expose information about leases
461    access(all) struct LeaseInfo {
462        access(all) let name: String
463        access(all) let address: Address
464        access(all) let cost: UFix64
465        access(all) let status: String
466        access(all) let validUntil: UFix64
467        access(all) let lockedUntil: UFix64
468        access(all) let addons: [String]
469
470        init(_ pointer: {FindLeaseMarket.LeasePointer}){
471            let network = FindLeaseMarket.getNetwork()
472            let name = pointer.name
473            let status= network.readStatus(name)
474            self.name=name
475            var s="TAKEN"
476            if status.status == FIND.LeaseStatus.FREE {
477                s="FREE"
478            } else if status.status == FIND.LeaseStatus.LOCKED {
479                s="LOCKED"
480            }
481            self.status=s
482            self.validUntil=network.getLeaseExpireTime(name)
483            self.lockedUntil=network.getLeaseLockedUntil(name)
484            self.address=status.owner!
485            self.cost=network.calculateCost(name)
486            if pointer.valid() {
487                let lease = pointer.borrow()
488                self.addons=lease.getAddon(name: name)
489            } else {
490                self.addons=[]
491            }
492        }
493
494    }
495
496    access(all) resource interface SaleItem {
497        //this is the type of sale this is, active, cancelled etc
498        access(all) fun getSaleType(): String
499        access(all) fun getSeller(): Address
500        access(all) fun getBuyer(): Address?
501
502        access(all) fun getSellerName() : String?
503        access(all) fun getBuyerName() : String?
504
505        access(all) fun toLeaseInfo() : FindLeaseMarket.LeaseInfo
506        access(all) fun checkPointer() : Bool
507        access(all) fun getListingType() : Type
508        access(all) fun getListingTypeIdentifier(): String
509
510        //the Type of the item for sale
511        access(all) fun getItemType(): Type
512        //The id of the nft for sale
513        access(all) fun getLeaseName() : String
514
515        access(all) fun getBalance(): UFix64
516        access(all) fun getAuction(): AuctionItem?
517        access(all) fun getFtType() : Type //The type of FT used for this sale item
518        access(all) fun getValidUntil() : UFix64? //A timestamp that says when this item is valid until
519
520        access(all) fun getSaleItemExtraField() : {String : AnyStruct}
521        access(all) fun getId() : UInt64
522    }
523
524    access(all) resource interface Bid {
525        access(all) fun getBalance() : UFix64
526        access(all) fun getSellerAddress() : Address
527        access(all) fun getBidExtraField() : {String : AnyStruct}
528    }
529
530    access(all) struct SaleItemInformation {
531        access(all) let leaseIdentifier: String
532        access(all) let leaseName: String
533        access(all) let seller: Address
534        access(all) let sellerName: String?
535        access(all) let amount: UFix64?
536        access(all) let bidder: Address?
537        access(all) var bidderName: String?
538        access(all) let listingId: UInt64
539
540        access(all) let saleType: String
541        access(all) let listingTypeIdentifier: String
542        access(all) let ftAlias: String
543        access(all) let ftTypeIdentifier: String
544        access(all) let listingValidUntil: UFix64?
545
546        access(all) var lease: LeaseInfo?
547        access(all) let auction: AuctionItem?
548        access(all) let listingStatus:String
549        access(all) let saleItemExtraField: {String : AnyStruct}
550
551        init(item: &{SaleItem}, status:String, leaseInfo: Bool) {
552            self.leaseIdentifier= item.getItemType().identifier
553            self.leaseName=item.getLeaseName()
554            self.listingStatus=status
555            self.saleType=item.getSaleType()
556            self.listingTypeIdentifier=item.getListingTypeIdentifier()
557            self.listingId=item.getId()
558            self.amount=item.getBalance()
559            self.bidder=item.getBuyer()
560            self.bidderName=item.getBuyerName()
561            self.seller=item.getSeller()
562            self.sellerName=item.getSellerName()
563            self.listingValidUntil=item.getValidUntil()
564            self.lease=nil
565            if leaseInfo {
566                if status != "stopped" {
567                    self.lease=item.toLeaseInfo()
568                }
569            }
570            let ftIdentifier=item.getFtType().identifier
571            self.ftTypeIdentifier=ftIdentifier
572            let ftInfo=FTRegistry.getFTInfoByTypeIdentifier(ftIdentifier)
573            self.ftAlias=ftInfo?.alias ?? ""
574
575            self.auction=item.getAuction()
576            self.saleItemExtraField=item.getSaleItemExtraField()
577        }
578    }
579
580    access(all) struct BidInfo{
581        access(all) let name: String
582        access(all) let bidAmount: UFix64
583        access(all) let bidTypeIdentifier: String
584        access(all) let timestamp: UFix64
585        access(all) let item: SaleItemInformation
586
587        init(name: String, bidTypeIdentifier: String, bidAmount: UFix64, timestamp: UFix64, item:SaleItemInformation) {
588            self.name=name
589            self.bidAmount=bidAmount
590            self.bidTypeIdentifier=bidTypeIdentifier
591            self.timestamp=timestamp
592            self.item=item
593        }
594    }
595
596    access(all) struct AuctionItem {
597        //end time
598        //current time
599        access(all) let startPrice: UFix64
600        access(all) let currentPrice: UFix64
601        access(all) let minimumBidIncrement: UFix64
602        access(all) let reservePrice: UFix64
603        access(all) let extentionOnLateBid: UFix64
604        access(all) let auctionEndsAt: UFix64?
605        access(all) let timestamp: UFix64
606
607        init(startPrice: UFix64, currentPrice: UFix64, minimumBidIncrement: UFix64, reservePrice: UFix64, extentionOnLateBid: UFix64, auctionEndsAt: UFix64? , timestamp: UFix64){
608            self.startPrice = startPrice
609            self.currentPrice = currentPrice
610            self.minimumBidIncrement = minimumBidIncrement
611            self.reservePrice = reservePrice
612            self.extentionOnLateBid = extentionOnLateBid
613            self.auctionEndsAt = auctionEndsAt
614            self.timestamp = timestamp
615        }
616    }
617
618    access(all) resource interface SaleItemCollectionPublic {
619        access(all) fun getNameSales(): [String]
620        access(all) fun containsNameSale(_ name: String): Bool
621        //TODO: verify this?
622        access(all) fun borrowSaleItem(_ name: String) : &{SaleItem}
623        access(all) fun getListingType() : Type
624    }
625
626    access(all) resource interface MarketBidCollectionPublic {
627        access(all) fun getNameBids() : [String]
628        access(all) fun containsNameBid(_ name: String): Bool
629        access(all) fun getBidType() : Type
630        access(all) fun borrowBidItem(_ name: String) : &{Bid}
631    }
632
633    access(all) struct GhostListing{
634        // access(all) let listingType: Type
635        access(all) let listingTypeIdentifier: String
636        access(all) let name: String
637
638
639        init(listingType:Type, name:String) {
640            //			self.listingType=listingType
641            self.listingTypeIdentifier=listingType.identifier
642            self.name=name
643        }
644    }
645
646    access(all) struct SaleItemCollectionReport {
647        access(all) let items : [FindLeaseMarket.SaleItemInformation]
648        access(all) let ghosts: [FindLeaseMarket.GhostListing]
649
650        init(items: [SaleItemInformation], ghosts: [GhostListing]) {
651            self.items=items
652            self.ghosts=ghosts
653        }
654    }
655
656    access(all) struct BidItemCollectionReport {
657        access(all) let items : [FindLeaseMarket.BidInfo]
658        access(all) let ghosts: [FindLeaseMarket.GhostListing]
659
660        init(items: [BidInfo], ghosts: [GhostListing]) {
661            self.items=items
662            self.ghosts=ghosts
663        }
664    }
665
666    access(contract) fun getNetwork() : &FIND.Network {
667        return FindLeaseMarket.account.storage.borrow<&FIND.Network>(from : FIND.NetworkStoragePath) ?? panic("Network is not up")
668    }
669
670    /* Admin Function */
671    access(account) fun addSaleItemType(_ type: Type) {
672        self.saleItemTypes.append(type)
673        FindMarket.addPathMap(type)
674        FindMarket.addListingName(type)
675    }
676
677    access(account) fun addMarketBidType(_ type: Type) {
678        self.marketBidTypes.append(type)
679        FindMarket.addPathMap(type)
680        FindMarket.addListingName(type)
681    }
682
683    access(account) fun addSaleItemCollectionType(_ type: Type) {
684        self.saleItemCollectionTypes.append(type)
685        FindMarket.addPathMap(type)
686        FindMarket.addListingName(type)
687    }
688
689    access(account) fun addMarketBidCollectionType(_ type: Type) {
690        self.marketBidCollectionTypes.append(type)
691        FindMarket.addPathMap(type)
692        FindMarket.addListingName(type)
693    }
694
695    access(account) fun removeSaleItemType(_ type: Type) {
696        var counter = 0
697        while counter < self.saleItemTypes.length {
698            if type == self.saleItemTypes[counter] {
699                self.saleItemTypes.remove(at: counter)
700            }
701            counter = counter + 1
702        }
703    }
704
705    access(account) fun removeMarketBidType(_ type: Type) {
706        var counter = 0
707        while counter < self.marketBidTypes.length {
708            if type == self.marketBidTypes[counter] {
709                self.marketBidTypes.remove(at: counter)
710            }
711            counter = counter + 1
712        }
713    }
714
715    access(account) fun removeSaleItemCollectionType(_ type: Type) {
716        var counter = 0
717        while counter < self.saleItemCollectionTypes.length {
718            if type == self.saleItemCollectionTypes[counter] {
719                self.saleItemCollectionTypes.remove(at: counter)
720            }
721            counter = counter + 1
722        }
723    }
724
725    access(account) fun removeMarketBidCollectionType(_ type: Type) {
726        var counter = 0
727        while counter < self.marketBidCollectionTypes.length {
728            if type == self.marketBidCollectionTypes[counter] {
729                self.marketBidCollectionTypes.remove(at: counter)
730            }
731            counter = counter + 1
732        }
733    }
734
735    init() {
736        self.saleItemTypes = []
737        self.saleItemCollectionTypes = []
738        self.marketBidTypes = []
739        self.marketBidCollectionTypes = []
740    }
741}
742