Smart Contract
FindLeaseMarket
A.097bafa4e0b48eef.FindLeaseMarket
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