Smart Contract

FindLeaseMarketDirectOfferSoft

A.097bafa4e0b48eef.FindLeaseMarketDirectOfferSoft

Deployed

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

Dependents

13 imports
1import FungibleToken from 0xf233dcee88fe0abe
2import FlowToken from 0x1654653399040a61
3import NonFungibleToken from 0x1d7e57aa55817448
4import MetadataViews from 0x1d7e57aa55817448
5import FindViews from 0x097bafa4e0b48eef
6import Clock from 0x097bafa4e0b48eef
7import Debug from 0x097bafa4e0b48eef
8import FIND from 0x097bafa4e0b48eef
9import FindMarket from 0x097bafa4e0b48eef
10import FindLeaseMarket from 0x097bafa4e0b48eef
11
12access(all) contract FindLeaseMarketDirectOfferSoft {
13
14    access(all) entitlement Seller
15
16    access(all) event DirectOffer(tenant: String, id: UInt64, saleID: UInt64, seller: Address, sellerName: String?, amount: UFix64, status: String, vaultType:String, leaseInfo: FindLeaseMarket.LeaseInfo?, buyer:Address?, buyerName:String?, buyerAvatar:String?, endsAt: UFix64?, previousBuyer:Address?, previousBuyerName:String?)
17
18    access(all) resource SaleItem : FindLeaseMarket.SaleItem {
19
20        access(contract) var pointer: {FindLeaseMarket.LeasePointer}
21        access(contract) var offerCallback: Capability<&MarketBidCollection>
22
23        access(contract) var directOfferAccepted:Bool
24        access(contract) var validUntil: UFix64?
25        access(contract) var saleItemExtraField: {String : AnyStruct}
26
27        init(pointer: FindLeaseMarket.ReadLeasePointer, callback: Capability<&MarketBidCollection>, validUntil: UFix64?, saleItemExtraField: {String : AnyStruct}) {
28            self.offerCallback=callback
29            self.directOfferAccepted=false
30            self.validUntil=validUntil
31            self.saleItemExtraField=saleItemExtraField
32            self.pointer=pointer
33        }
34
35        access(all) fun getName() : String {
36            return self.pointer.name
37        }
38
39        access(contract) fun acceptDirectOffer() {
40            self.directOfferAccepted=true
41        }
42
43        //Here we do not get a vault back, it is sent in to the method itself
44        access(contract) fun acceptNonEscrowedBid() {
45            pre{
46                self.offerCallback.check() : "Bidder unlinked the bid collection capability."
47                self.pointer != nil : "Please accept offer"
48            }
49            self.offerCallback.borrow()!.acceptNonEscrowed(self.getLeaseName())
50            let pointer = self.pointer as! FindLeaseMarket.AuthLeasePointer
51            pointer.move(to: self.offerCallback.address)
52        }
53
54        access(all) fun getFtType() : Type {
55            pre{
56                self.offerCallback.check() : "Bidder unlinked the bid collection capability."
57            }
58            return self.offerCallback.borrow()!.getVaultType(self.getLeaseName())
59        }
60
61        access(all) fun getLeaseName() : String {
62            return self.pointer.name
63        }
64
65        access(all) fun getItemType() : Type {
66            return Type<@FIND.Lease>()
67        }
68
69        access(all) fun getAuction(): FindLeaseMarket.AuctionItem? {
70            return nil
71        }
72
73        access(all) fun getId() : UInt64 {
74            return self.pointer.getUUID()
75        }
76
77        access(all) fun getSaleType() : String {
78            if self.directOfferAccepted {
79                return "active_finished"
80            }
81            return "active_ongoing"
82        }
83
84        access(all) fun getListingType() : Type {
85            return Type<@SaleItem>()
86        }
87
88        access(all) fun getListingTypeIdentifier() : String {
89            return Type<@SaleItem>().identifier
90        }
91
92        access(all) fun getBalance() : UFix64 {
93            pre{
94                self.offerCallback.check() : "Bidder unlinked the bid collection capability."
95            }
96            return self.offerCallback.borrow()!.getBalance(self.getLeaseName())
97        }
98
99        access(all) fun getSeller() : Address {
100            return self.pointer.owner()
101        }
102
103        access(all) fun getSellerName() : String? {
104            let address = self.pointer.owner()
105            return FIND.reverseLookup(address)
106        }
107
108        access(all) fun getBuyer() : Address? {
109            return self.offerCallback.address
110        }
111
112        access(all) fun getBuyerName() : String? {
113            if let name = FIND.reverseLookup(self.offerCallback.address) {
114                return name
115            }
116            return nil
117        }
118
119        access(all) fun toLeaseInfo() : FindLeaseMarket.LeaseInfo{
120            return FindLeaseMarket.LeaseInfo(self.pointer)
121        }
122
123        access(contract) fun setValidUntil(_ time: UFix64?) {
124            self.validUntil=time
125        }
126
127        access(all) fun getValidUntil() : UFix64? {
128            return self.validUntil
129        }
130
131        access(contract) fun setPointer(_ pointer: FindLeaseMarket.AuthLeasePointer) {
132            self.pointer=pointer
133        }
134
135        access(contract) fun setCallback(_ callback: Capability<&MarketBidCollection>) {
136            self.offerCallback=callback
137        }
138
139        access(all) fun checkPointer() : Bool {
140            return self.pointer.valid()
141        }
142
143        access(all) fun getSaleItemExtraField() : {String : AnyStruct} {
144            return self.saleItemExtraField
145        }
146
147        access(contract) fun setSaleItemExtraField(_ field: {String : AnyStruct}) {
148            self.saleItemExtraField = field
149        }
150
151    }
152
153    access(all) resource interface SaleItemCollectionPublic {
154        //fetch all the tokens in the collection
155        access(all) fun getNameSales(): [String]
156        access(all) fun containsNameSale(_ name: String): Bool
157        access(contract) fun cancelBid(_ name: String)
158        access(contract) fun registerIncreasedBid(_ name: String)
159
160        //place a bid on a token
161        access(contract) fun registerBid(name: String, callback: Capability<&MarketBidCollection>, validUntil: UFix64?, saleItemExtraField: {String : AnyStruct})
162
163        access(contract) fun isAcceptedDirectOffer(_ name:String) : Bool
164
165        access(contract) fun fulfillDirectOfferNonEscrowed(name:String, vault: @{FungibleToken.Vault})
166
167    }
168
169    access(all) resource SaleItemCollection: SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic {
170        //is this the best approach now or just put the NFT inside the saleItem?
171        access(contract) var items: @{String: SaleItem}
172
173        access(contract) let tenantCapability: Capability<&FindMarket.Tenant>
174
175        init (_ tenantCapability: Capability<&FindMarket.Tenant>) {
176            self.items <- {}
177            self.tenantCapability=tenantCapability
178        }
179
180        access(self) fun getTenant() : &FindMarket.Tenant {
181            pre{
182                self.tenantCapability.check() : "Tenant client is not linked anymore"
183            }
184            return self.tenantCapability.borrow()!
185        }
186
187        access(contract) fun isAcceptedDirectOffer(_ name:String) : Bool{
188            pre {
189                self.items.containsKey(name) : "Invalid name sale=".concat(name)
190            }
191            let saleItem = self.borrow(name)
192
193            return saleItem.directOfferAccepted
194        }
195
196        access(all) fun getListingType() : Type {
197            return Type<@SaleItem>()
198        }
199
200        //this is called when a buyer cancel a direct offer
201        access(contract) fun cancelBid(_ name: String) {
202            pre {
203                self.items.containsKey(name) : "Invalid name sale=".concat(name)
204            }
205            let saleItem=self.borrow(name)
206
207            let actionResult=self.getTenant().allowedAction(listingType: self.getListingType(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType(), action: FindMarket.MarketAction(listing:false, name:"cancel bid in direct offer soft"), seller: nil, buyer: nil)
208
209            if !actionResult.allowed {
210                panic(actionResult.message)
211            }
212
213            self.emitEvent(saleItem: saleItem, status: "cancel", previousBuyer: nil)
214            destroy <- self.items.remove(key: name)
215        }
216
217
218        access(self) fun emitEvent(saleItem: &SaleItem, status: String, previousBuyer:Address?) {
219            let owner=saleItem.getSeller()
220            let ftType=saleItem.getFtType()
221            let balance=saleItem.getBalance()
222            let buyer=saleItem.getBuyer()!
223            let buyerName=FIND.reverseLookup(buyer)
224            let profile = FIND.lookup(buyer.toString())
225
226            var leaseInfo:FindLeaseMarket.LeaseInfo?=nil
227            if saleItem.checkPointer() {
228                leaseInfo=saleItem.toLeaseInfo()
229            }
230
231            var previousBuyerName : String?=nil
232            if let pb= previousBuyer {
233                previousBuyerName = FIND.reverseLookup(pb)
234            }
235
236            emit DirectOffer(tenant:self.getTenant().name, id: saleItem.getId(), saleID: saleItem.uuid, seller:owner, sellerName: FIND.reverseLookup(owner), amount: balance, status:status, vaultType: ftType.identifier, leaseInfo:leaseInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile?.getAvatar(), endsAt: saleItem.validUntil, previousBuyer:previousBuyer, previousBuyerName:previousBuyerName)
237        }
238
239
240        //The only thing we do here is basically register an event
241        access(contract) fun registerIncreasedBid(_ name: String) {
242            pre {
243                self.items.containsKey(name) : "Invalid name sale=".concat(name)
244            }
245            let saleItem=self.borrowAuth(name)
246
247            let actionResult=self.getTenant().allowedAction(listingType: self.getListingType(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType(), action: FindMarket.MarketAction(listing:true, name:"increase bid in direct offer soft"), seller: self.owner!.address, buyer: saleItem.offerCallback.address)
248
249            if !actionResult.allowed {
250                panic(actionResult.message)
251            }
252
253            self.emitEvent(saleItem: saleItem, status: "active_offered", previousBuyer:nil)
254        }
255
256
257        //This is a function that buyer will call (via his bid collection) to register the bicCallback with the seller
258        access(contract) fun registerBid(name: String, callback: Capability<&MarketBidCollection>, validUntil: UFix64?, saleItemExtraField: {String : AnyStruct}) {
259
260            //If there are no bids from anybody else before we need to make the item
261            if !self.items.containsKey(name) {
262                let item = FindLeaseMarket.ReadLeasePointer(name: name)
263                let saleItem <- create SaleItem(pointer: item, callback: callback, validUntil: validUntil, saleItemExtraField: saleItemExtraField)
264                let actionResult=self.getTenant().allowedAction(listingType: self.getListingType(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType(), action: FindMarket.MarketAction(listing:true, name:"bid in direct offer soft"), seller: self.owner!.address, buyer: callback.address)
265
266                if !actionResult.allowed {
267                    panic(actionResult.message)
268                }
269                self.items[name] <-! saleItem
270                let saleItemRef=self.borrow(name)
271                self.emitEvent(saleItem: saleItemRef, status: "active_offered", previousBuyer:nil)
272                return
273            }
274
275
276            let saleItem=self.borrowAuth(name)
277            if self.borrow(name).getBuyer()! == callback.address {
278                panic("You already have the latest bid on this item, use the incraseBid transaction")
279            }
280
281            let actionResult=self.getTenant().allowedAction(listingType: self.getListingType(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType(), action: FindMarket.MarketAction(listing:true, name:"bid in direct offer soft"), seller: self.owner!.address, buyer: callback.address)
282
283            if !actionResult.allowed {
284                panic(actionResult.message)
285            }
286
287            let balance=callback.borrow()?.getBalance(name) ?? panic("Bidder unlinked the bid collection capability. bidder address : ".concat(callback.address.toString()))
288
289            let currentBalance=saleItem.getBalance()
290            Debug.log("currentBalance=".concat(currentBalance.toString()).concat(" new bid is at=").concat(balance.toString()))
291            if currentBalance >= balance {
292                panic("There is already a higher bid on this item. Current bid : ".concat(currentBalance.toString()).concat(" . New bid is at : ").concat(balance.toString()))
293            }
294            let previousBuyer=saleItem.offerCallback.address
295            //somebody else has the highest item so we cancel it
296            saleItem.offerCallback.borrow()!.cancelBidFromSaleItem(name)
297            saleItem.setValidUntil(validUntil)
298            saleItem.setSaleItemExtraField(saleItemExtraField)
299            saleItem.setCallback(callback)
300
301            self.emitEvent(saleItem: saleItem, status: "active_offered", previousBuyer:previousBuyer)
302
303        }
304
305
306        //cancel will reject a direct offer
307        access(Seller) fun cancel(_ name: String) {
308            pre {
309                self.items.containsKey(name) : "Invalid name sale=".concat(name)
310            }
311
312            let saleItem=self.borrowAuth(name)
313
314            let actionResult=self.getTenant().allowedAction(listingType: self.getListingType(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType(), action: FindMarket.MarketAction(listing:false, name:"reject offer in direct offer soft"), seller: nil, buyer: nil)
315
316            if !actionResult.allowed {
317                panic(actionResult.message)
318            }
319
320            self.emitEvent(saleItem: saleItem, status: "cancel_rejected", previousBuyer:nil)
321            if !saleItem.offerCallback.check() {
322                panic("Seller unlinked the SaleItem collection capability. seller address : ".concat(saleItem.offerCallback.address.toString()))
323            }
324            saleItem.offerCallback.borrow()!.cancelBidFromSaleItem(name)
325            destroy <- self.items.remove(key: name)
326        }
327
328        access(Seller) fun acceptOffer(_ pointer: FindLeaseMarket.AuthLeasePointer) {
329            pre {
330                self.items.containsKey(pointer.name) : "Invalid name sale=".concat(pointer.name)
331            }
332
333            let saleItem = self.borrowAuth(pointer.name)
334
335            if saleItem.validUntil != nil && saleItem.validUntil! < Clock.time() {
336                panic("This direct offer is already expired")
337            }
338
339            let actionResult=self.getTenant().allowedAction(listingType: self.getListingType(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType(), action: FindMarket.MarketAction(listing:false, name:"accept offer in direct offer soft"), seller: self.owner!.address, buyer: saleItem.offerCallback.address)
340
341            if !actionResult.allowed {
342                panic(actionResult.message)
343            }
344
345            //Set the auth pointer in the saleItem so that it now can be fulfilled
346            saleItem.setPointer(pointer)
347            saleItem.acceptDirectOffer()
348
349            self.emitEvent(saleItem: saleItem, status: "active_accepted", previousBuyer:nil)
350        }
351
352        /// this is called from a bid when a seller accepts
353        access(contract) fun fulfillDirectOfferNonEscrowed(name:String, vault: @{FungibleToken.Vault}) {
354            pre {
355                self.items.containsKey(name) : "Invalid name sale=".concat(name)
356            }
357
358            let saleItem = self.borrowAuth(name)
359            if !saleItem.directOfferAccepted {
360                panic("cannot fulfill a direct offer that is not accepted yet")
361            }
362
363            if vault.getType() != saleItem.getFtType() {
364                panic("The FT vault sent in to fulfill does not match the required type. Required Type : ".concat(saleItem.getFtType().identifier).concat(" . Sent-in vault type : ".concat(vault.getType().identifier)))
365            }
366            let actionResult=self.getTenant().allowedAction(listingType: self.getListingType(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType(), action: FindMarket.MarketAction(listing:false, name:"fulfill directOffer"), seller: self.owner!.address, buyer: saleItem.offerCallback.address)
367
368            if !actionResult.allowed {
369                panic(actionResult.message)
370            }
371
372            let cuts= self.getTenant().getCuts(name: actionResult.name, listingType: self.getListingType(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType())
373
374            self.emitEvent(saleItem: saleItem, status: "sold", previousBuyer:nil)
375            let leaseInfo=saleItem.toLeaseInfo()
376            saleItem.acceptNonEscrowedBid()
377            FindLeaseMarket.pay(tenant: self.getTenant().name, leaseName:name, saleItem: saleItem, vault: <- vault, leaseInfo: leaseInfo, cuts:cuts)
378
379            destroy <- self.items.remove(key: name)
380        }
381
382        access(all) fun getNameSales(): [String] {
383            return self.items.keys
384        }
385
386        access(all) fun containsNameSale(_ name: String): Bool {
387            return self.items.containsKey(name)
388        }
389
390        access(all) fun borrow(_ name: String): &SaleItem {
391            pre{
392                self.items.containsKey(name) : "This name sale does not exist.".concat(name)
393            }
394            return (&self.items[name])!
395        }
396
397        access(Seller) fun borrowAuth(_ name: String): auth(Seller) &SaleItem {
398            pre{
399                self.items.containsKey(name) : "This name sale does not exist.".concat(name)
400            }
401            return (&self.items[name])!
402        }
403
404        access(all) fun borrowSaleItem(_ name: String) : &{FindLeaseMarket.SaleItem} {
405            pre{
406                self.items.containsKey(name) : "This name sale does not exist.".concat(name)
407            }
408            return (&self.items[name])!
409        }
410    }
411
412    /*
413    ==========================================================================
414    Bids are a collection/resource for storing the bids bidder made on leases
415    ==========================================================================
416    */
417
418    access(all) resource Bid : FindLeaseMarket.Bid {
419        access(contract) let from: Capability<&SaleItemCollection>
420        access(contract) let leaseName: String
421
422        //this should reflect on what the above uuid is for
423        access(contract) let vaultType: Type
424        access(contract) var bidAt: UFix64
425        access(contract) var balance: UFix64 //This is what you bid for non escrowed bids
426        access(contract) let bidExtraField: {String : AnyStruct}
427
428        init(from: Capability<&SaleItemCollection>, leaseName: String, vaultType:Type,  nonEscrowedBalance:UFix64, bidExtraField: {String : AnyStruct}){
429            self.vaultType= vaultType
430            self.balance=nonEscrowedBalance
431            self.leaseName=leaseName
432            self.from=from
433            self.bidAt=Clock.time()
434            self.bidExtraField=bidExtraField
435        }
436
437        access(contract) fun setBidAt(_ time: UFix64) {
438            self.bidAt=time
439        }
440
441        access(contract) fun increaseBid(_ amount:UFix64) {
442            self.balance=self.balance+amount
443        }
444
445        access(all) fun getBalance() : UFix64 {
446            return self.balance
447        }
448
449        access(all) fun getSellerAddress() : Address {
450            return self.from.address
451        }
452
453        access(all) fun getBidExtraField() : {String : AnyStruct} {
454            return self.bidExtraField
455        }
456    }
457
458    access(all) resource interface MarketBidCollectionPublic {
459        access(all) fun getBalance(_ name: String) : UFix64
460        access(all) fun getVaultType(_ name: String) : Type
461        access(all) fun containsNameBid(_ name: String): Bool
462        access(all) fun getNameBids() : [String]
463        access(contract) fun acceptNonEscrowed(_ name: String)
464        access(contract) fun cancelBidFromSaleItem(_ name: String)
465    }
466
467    access(all) entitlement Buyer
468
469    //A collection stored for bidders/buyers
470    access(all) resource MarketBidCollection: MarketBidCollectionPublic, FindLeaseMarket.MarketBidCollectionPublic {
471
472        access(contract) var bids : @{String: Bid}
473        access(contract) let receiver: Capability<&{FungibleToken.Receiver}>
474        access(contract) let tenantCapability: Capability<&FindMarket.Tenant>
475
476        //not sure we can store this here anymore. think it needs to be in every bid
477        init(receiver: Capability<&{FungibleToken.Receiver}>, tenantCapability: Capability<&FindMarket.Tenant>) {
478            self.bids <- {}
479            self.receiver=receiver
480            self.tenantCapability=tenantCapability
481        }
482
483        access(self) fun getTenant() : &FindMarket.Tenant {
484            pre{
485                self.tenantCapability.check() : "Tenant client is not linked anymore"
486            }
487            return self.tenantCapability.borrow()!
488        }
489
490        //called from lease when auction is ended
491        access(contract) fun acceptNonEscrowed(_ name: String) {
492            let bid <- self.bids.remove(key: name) ?? panic("missing bid")
493            destroy bid
494        }
495
496        access(all) fun getVaultType(_ name:String) : Type {
497            return self.borrowBid(name).vaultType
498        }
499
500        access(all) fun getNameBids() : [String] {
501            return self.bids.keys
502        }
503
504        access(all) fun containsNameBid(_ name: String) : Bool {
505            return self.bids.containsKey(name)
506        }
507
508        access(all) fun getBidType() : Type {
509            return Type<@Bid>()
510        }
511
512
513        access(Buyer) fun bid(name: String, amount:UFix64, vaultType:Type, validUntil: UFix64?, saleItemExtraField: {String : AnyStruct}, bidExtraField: {String : AnyStruct}) {
514            if self.owner!.address == FIND.status(name).owner! {
515                panic("You cannot bid on your own resource")
516            }
517
518            if self.bids[name] !=nil{
519                panic("You already have an bid for this item, use increaseBid on that bid")
520            }
521
522            // ensure it is not a 0 dollar listing
523            if amount <= 0.0 {
524                panic("Offer price should be greater than 0")
525            }
526
527            // ensure validUntil is valid
528            if validUntil != nil && validUntil! < Clock.time() {
529                panic("Valid until is before current time")
530            }
531
532            let from=getAccount(FIND.status(name).owner!).capabilities.get<&SaleItemCollection>(self.getTenant().getPublicPath(Type<@SaleItemCollection>()))
533
534            let bid <- create Bid(from: from, leaseName: name, vaultType: vaultType, nonEscrowedBalance:amount, bidExtraField: bidExtraField)
535            let saleItemCollection= from.borrow() ?? panic("Could not borrow sale item for name=".concat(name))
536            let callbackCapability =self.owner!.capabilities.get<&MarketBidCollection>(self.getTenant().getPublicPath(Type<@MarketBidCollection>()))
537
538            let oldToken <- self.bids[name] <- bid
539            saleItemCollection.registerBid(name: name, callback: callbackCapability, validUntil: validUntil, saleItemExtraField: saleItemExtraField)
540            destroy oldToken
541        }
542
543        access(all) fun fulfillDirectOffer(name:String, vault: @{FungibleToken.Vault}) {
544            pre {
545                self.bids[name] != nil : "You need to have a bid here already"
546            }
547
548            let bid =self.borrowBid(name)
549            let saleItem=bid.from.borrow()!
550
551            if !saleItem.isAcceptedDirectOffer(name) {
552                panic("offer is not accepted yet")
553            }
554
555            saleItem.fulfillDirectOfferNonEscrowed(name:name, vault: <- vault)
556        }
557
558        access(Buyer) fun increaseBid(name: String, increaseBy: UFix64) {
559            let bid =self.borrowBid(name)
560            bid.setBidAt(Clock.time())
561            bid.increaseBid(increaseBy)
562            if !bid.from.check() {
563                panic("Seller unlinked the SaleItem collection capability. seller address : ".concat(bid.from.address.toString()))
564            }
565            bid.from.borrow()!.registerIncreasedBid(name)
566        }
567
568        /// The users cancel a bid himself
569        access(Buyer) fun cancelBid(_ name: String) {
570            let bid= self.borrowBid(name)
571            if !bid.from.check() {
572                panic("Seller unlinked the SaleItem collection capability. seller address : ".concat(bid.from.address.toString()))
573            }
574            bid.from.borrow()!.cancelBid(name)
575            self.cancelBidFromSaleItem(name)
576        }
577
578        //called from saleItem when things are cancelled
579        //if the bid is canceled from seller then we move the vault tokens back into your vault
580        access(contract) fun cancelBidFromSaleItem(_ name: String) {
581            let bid <- self.bids.remove(key: name) ?? panic("missing bid")
582            destroy bid
583        }
584
585        access(all) fun borrowBid(_ name: String): &Bid {
586            pre{
587                self.bids.containsKey(name) : "This name bid does not exist.".concat(name)
588            }
589            return (&self.bids[name])!
590        }
591
592        access(all) fun borrowBidItem(_ name: String): &{FindLeaseMarket.Bid} {
593            pre{
594                self.bids.containsKey(name) : "This name bid does not exist.".concat(name)
595            }
596            return (&self.bids[name])!
597        }
598
599        access(all) fun getBalance(_ name: String) : UFix64 {
600            let bid= self.borrowBid(name)
601            return bid.balance
602        }
603    }
604
605    //Create an empty lease collection that store your leases to a name
606    access(all) fun createEmptySaleItemCollection(_ tenantCapability: Capability<&FindMarket.Tenant>) : @SaleItemCollection {
607        return <- create SaleItemCollection(tenantCapability)
608    }
609
610    access(all) fun createEmptyMarketBidCollection(receiver: Capability<&{FungibleToken.Receiver}>, tenantCapability: Capability<&FindMarket.Tenant>) : @MarketBidCollection {
611        return <- create MarketBidCollection(receiver: receiver, tenantCapability:tenantCapability)
612    }
613
614    access(all) fun getSaleItemCapability(marketplace:Address, user:Address) : Capability<&{SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic}>? {
615        if  FindMarket.getTenantCapability(marketplace) == nil {
616            panic("Invalid tenant")
617        }
618        if let tenant=FindMarket.getTenantCapability(marketplace)!.borrow() {
619
620            return getAccount(user).capabilities.get<&{SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic}>(tenant.getPublicPath(Type<@SaleItemCollection>()))
621        }
622        return nil
623    }
624
625    access(all) fun getBidCapability( marketplace:Address, user:Address) : Capability<&{MarketBidCollectionPublic, FindLeaseMarket.MarketBidCollectionPublic}>? {
626        if  FindMarket.getTenantCapability(marketplace) == nil {
627            panic("Invalid tenant")
628        }
629        if let tenant=FindMarket.getTenantCapability(marketplace)!.borrow() {
630            return getAccount(user).capabilities.get<&{MarketBidCollectionPublic, FindLeaseMarket.MarketBidCollectionPublic}>(tenant.getPublicPath(Type<@MarketBidCollection>()))
631        }
632        return nil
633    }
634
635    init() {
636        FindLeaseMarket.addSaleItemType(Type<@SaleItem>())
637        FindLeaseMarket.addSaleItemCollectionType(Type<@SaleItemCollection>())
638        FindLeaseMarket.addMarketBidType(Type<@Bid>())
639        FindLeaseMarket.addMarketBidCollectionType(Type<@MarketBidCollection>())
640    }
641}
642