Smart Contract
TrmMarketV2_1_1
A.61fc4b873e58733b.TrmMarketV2_1_1
1/**
2
3 TrmMarketV2_1_1.cdc
4
5 Description: Contract definitions for users to sell and/or rent out their assets
6
7 Marketplace is where users can create a sale collection that they
8 store in their account storage. In the sale collection,
9 they can put their NFTs up for sale/rent with a price and publish a
10 reference so that others can see the sale.
11
12 If another user sees an NFT that they want to buy,
13 they can send fungible tokens that equal the buy price
14 to buy the NFT. The NFT is transferred to them when
15 they make the purchase.
16
17 If another user sees an NFT that they want to rent,
18 they can send fungible tokens that equal the rent price
19 to rent the NFT. The Rent NFT will be minted and
20 transferred to them.
21
22 Each user who wants to sell/rent out tokens will have a sale
23 collection instance in their account that contains price information
24 for each node in their collection. The sale holds a capability that
25 links to their main asset collection.
26
27 They can give a reference to this collection to a central contract
28 so that it can list the sales in a central place
29
30 When a user creates a sale, they will supply four arguments:
31 - A TrmAssetV2_1.Collection capability that allows their sale to withdraw an asset when it is purchased.
32 - A FungibleToken.Receiver capability as the place where the payment for the token goes.
33 - A FungibleToken.Receiver capability specifying a beneficiary, where a cut of the purchase gets sent.
34 - A cut percentage, specifying how much the beneficiary will recieve.
35
36 The cut percentage can be set to zero if the user desires and they
37 will receive the entirety of the purchase. Trm will initialize sales
38 for users with the Trm admin vault as the vault where cuts get
39 deposited to.
40**/
41
42import TrmAssetV2_1 from 0x61fc4b873e58733b
43import TrmRentV2_1 from 0x61fc4b873e58733b
44import NonFungibleToken from 0x1d7e57aa55817448
45
46pub contract TrmMarketV2_1_1 {
47 /// -----------------------------------------------------------------------
48 /// TRM Market contract Event definitions
49 /// -----------------------------------------------------------------------
50
51 /// Event that emitted when the NFT contract is initialized
52 pub event ContractInitialized()
53 /// Emitted when an Asset is listed for transfer
54 pub event AssetListedForTransfer(assetTokenID: UInt64, salePrice: UFix64?, auctionPrice: UFix64?, auctionStartTimestamp: UFix64?, auctionPeriodSeconds: UFix64?, seller: Address?)
55 /// Emitted when an Asset is listed for transfer
56 pub event AssetBatchListedForTransfer(assetTokenIDs: [UInt64], salePrice: UFix64?, auctionPrice: UFix64?, auctionStartTimestamp: UFix64?, auctionPeriodSeconds: UFix64?, seller: Address?)
57 /// Emitted when an Asset is listed for rent
58 pub event AssetListedForRent(assetTokenID: UInt64, price: UFix64?, rentalPeriodSeconds: UFix64, seller: Address?)
59 /// Emitted when an Asset is listed for rent
60 pub event AssetBatchListedForRent(assetTokenIDs: [UInt64], price: UFix64?, rentalPeriodSeconds: UFix64, seller: Address?)
61 /// Emitted when the sale price of a listed asset has changed
62 pub event AssetTransferListingChanged(assetTokenID: UInt64, salePrice: UFix64?, auctionPrice: UFix64?, auctionStartTimestamp: UFix64?, auctionPeriodSeconds: UFix64?, seller: Address?)
63 /// Emitted when the sale price of a listed asset has changed
64 pub event AssetBatchTransferListingChanged(assetTokenIDs: [UInt64], salePrice: UFix64?, auctionPrice: UFix64?, auctionStartTimestamp: UFix64?, auctionPeriodSeconds: UFix64?, seller: Address?)
65 /// Emitted when the rent price of a listed asset has changed
66 pub event AssetRentListingChanged(assetTokenID: UInt64, price: UFix64?, rentalPeriodSeconds: UFix64, seller: Address?)
67 /// Emitted when the rent price of a listed asset has changed
68 pub event AssetBatchRentListingChanged(assetTokenIDs: [UInt64], price: UFix64?, rentalPeriodSeconds: UFix64, seller: Address?)
69 /// Emitted when a token is purchased from the market
70 pub event AssetTransferred(assetTokenID: UInt64, price: UFix64, seller: Address?, buyer: Address?, paymentID: String)
71 /// Emitted when a token is rented from the market
72 pub event AssetRented(assetTokenID: UInt64, rentID: UInt64, price: UFix64, expiryTimestamp: UFix64, assetName: String, assetDescription: String, assetURL: String, assetThumbnailURL: String, assetMetadata: {String: String}, kID: String, seller: Address?, buyer: Address?, rentalPeriodSeconds: UFix64, paymentID: String)
73 /// Emitted when a token has been delisted for sale
74 pub event AssetDelistedForTransfer(assetTokenID: UInt64, owner: Address?)
75 /// Emitted when a token has been delisted for sale
76 pub event AssetBatchDelistedForTransfer(assetTokenIDs: [UInt64], owner: Address?)
77 /// Emitted when a token has been delisted for rent
78 pub event AssetDelistedForRent(assetTokenID: UInt64, owner: Address?)
79 /// Emitted when a token has been delisted for rent
80 pub event AssetBatchDelistedForRent(assetTokenIDs: [UInt64], owner: Address?)
81
82 /// Path where the `SaleCollection` is stored
83 pub let marketStoragePath: StoragePath
84 /// Path where the public capability for the `SaleCollection` is
85 pub let marketPublicPath: PublicPath
86 /// Path where the private capability for the `SaleCollection` is
87 pub let marketPrivatePath: PrivatePath
88 /// Path where the 'Admin' resource is stored
89 pub let adminStoragePath: StoragePath
90
91 /// The private capability for minting rent tokens
92 pub var minterCapability: Capability<&TrmRentV2_1.Minter>
93
94 pub resource RentListing {
95 pub var price: UFix64
96 pub var rentalPeriodSeconds: UFix64
97
98 access(contract) fun setRentalPeriodSeconds(seconds: UFix64) {
99 self.rentalPeriodSeconds = seconds
100 }
101
102 init(rentalPeriodSeconds: UFix64) {
103 self.price = UFix64(0)
104 self.rentalPeriodSeconds = rentalPeriodSeconds
105 }
106 }
107
108 pub resource TransferListing {
109 pub var price: UFix64
110
111 init() {
112 self.price = UFix64(0)
113 }
114 }
115
116 /// SalePublic
117 //
118 /// The interface that a user can publish a capability to their sale
119 /// to allow others to access their sale
120 pub resource interface SalePublic {
121 access(contract) fun listForTransfer(tokenID: UInt64, salePrice: UFix64?, auctionPrice: UFix64?, auctionStartTimestamp: UFix64?, auctionPeriodSeconds: UFix64?)
122 access(contract) fun listForRent(tokenID: UInt64, price: UFix64?, rentalPeriodSeconds: UFix64?)
123 access(contract) fun batchListForTransfer(tokenIDs: [UInt64], salePrice: UFix64?, auctionPrice: UFix64?, auctionStartTimestamp: UFix64?, auctionPeriodSeconds: UFix64?)
124 access(contract) fun batchListForRent(tokenIDs: [UInt64], price: UFix64?, rentalPeriodSeconds: UFix64?)
125 access(contract) fun cancelTransfer(tokenID: UInt64)
126 access(contract) fun cancelRent(tokenID: UInt64)
127 access(contract) fun batchCancelTransfer(tokenIDs: [UInt64])
128 access(contract) fun batchCancelRent(tokenIDs: [UInt64])
129 access(contract) fun transfer(tokenID: UInt64, adminAccount: &TrmAssetV2_1.Admin, recipientAddress: Address, price: UFix64, paymentID: String)
130 access(contract) fun rent(tokenID: UInt64, price: UFix64, recipient: Capability<&{TrmRentV2_1.CollectionPublic}>, paymentID: String): UInt64
131
132 pub fun getTransferListing(tokenID: UInt64): &TransferListing?
133 pub fun getRentListing(tokenID: UInt64): &RentListing?
134 pub fun getTransferIDs(): [UInt64]
135 pub fun getRentIDs(): [UInt64]
136 pub fun borrowAsset(id: UInt64): &TrmAssetV2_1.NFT? {
137 /// If the result isn't nil, the id of the returned reference
138 /// should be the same as the argument to the function
139 post {
140 (result == nil) || (result?.id == id):
141 "Cannot borrow Asset reference: The ID of the returned reference is incorrect"
142 }
143 }
144 }
145
146 /// SaleCollection
147 ///
148 /// This is the main resource that token sellers will store in their account
149 /// to manage the NFTs that they are selling/renting. The SaleCollection keeps
150 /// track of the price of each token.
151 ///
152 /// When a token is purchased, a cut is taken from the tokens
153 /// and sent to the beneficiary, then the rest are sent to the seller.
154 ///
155 /// The seller chooses who the beneficiary is and what percentage
156 /// of the tokens gets taken from the purchase
157 pub resource SaleCollection: SalePublic {
158
159 /// A reference to collection of the user's assets
160 access(self) var ownerCollection: Capability<&TrmAssetV2_1.Collection>
161
162 /// Dictionary of the transfer prices for each NFT by ID
163 access(self) var transferListings: @{UInt64: TransferListing}
164
165 /// Dictionary of the rent prices for each NFT by ID
166 access(self) var rentListings: @{UInt64: RentListing}
167
168 init (ownerCollection: Capability<&TrmAssetV2_1.Collection>) {
169 pre {
170 /// Check that the owner's asset collection capability is correct
171 ownerCollection.check():
172 "Owner's Asset Collection Capability is invalid!"
173 }
174
175 /// create an empty collection to store the assets that are for transfer and rent
176 self.ownerCollection = ownerCollection
177
178 /// prices are initially empty because there are no assets for transfer and rent
179 self.transferListings <- {}
180 self.rentListings <- {}
181 }
182
183 destroy() {
184 destroy self.transferListings
185 destroy self.rentListings
186 }
187
188 /// listForTransfer lists an NFT for transfer in this transfer collection at the specified price, or updates an existing listing
189 ///
190 /// Parameters: tokenID: The id of the NFT to be put up for transfer
191 /// salePrice: The sale price of the NFT(This is just returned back as an event)
192 /// auctionPrice: The auction price of the NFT(This is just returned back as an event)
193 /// auctionStartTimestamp: The auction start timestamp
194 /// auctionPeriodSeconds: The period for which auction will last
195 access(contract) fun listForTransfer(tokenID: UInt64, salePrice: UFix64?, auctionPrice: UFix64?, auctionStartTimestamp: UFix64?, auctionPeriodSeconds: UFix64?) {
196 pre {
197 self.ownerCollection.borrow()!.idExists(id: tokenID):
198 "Asset does not exist in the owner's collection"
199 }
200
201 if self.transferListings.containsKey(tokenID) {
202 emit AssetTransferListingChanged(assetTokenID: tokenID, salePrice: salePrice, auctionPrice: auctionPrice, auctionStartTimestamp: auctionStartTimestamp, auctionPeriodSeconds: auctionPeriodSeconds, seller: self.owner?.address)
203 } else {
204 let oldTransferListing <- self.transferListings[tokenID] <- create TransferListing()
205 destroy oldTransferListing
206
207 emit AssetListedForTransfer(assetTokenID: tokenID, salePrice: salePrice, auctionPrice: auctionPrice, auctionStartTimestamp: auctionStartTimestamp, auctionPeriodSeconds: auctionPeriodSeconds, seller: self.owner?.address)
208 }
209 }
210
211 /// listForRent lists an NFT for rent in this sale collection at the specified price and rental period, or updates an existing listing
212 ///
213 /// Parameters: tokenID: The id of the NFT to be put up for rent
214 /// price: The rent price of the NFT(This is just returned back as an event)
215 /// rentalPeriodSeconds: The rental period (in seconds)
216 access(contract) fun listForRent(tokenID: UInt64, price: UFix64?, rentalPeriodSeconds: UFix64?) {
217 pre {
218 self.ownerCollection.borrow()!.idExists(id: tokenID):
219 "Asset does not exist in the owner's collection"
220 }
221
222 if let rentListing <- self.rentListings.remove(key: tokenID) {
223 if(rentalPeriodSeconds != nil) {
224 rentListing.setRentalPeriodSeconds(seconds: rentalPeriodSeconds!)
225 }
226
227 let oldRentListing <- self.rentListings[tokenID] <- rentListing
228 destroy oldRentListing
229
230 let rentListingRef = (&self.rentListings[tokenID] as &RentListing?)!
231
232 emit AssetRentListingChanged(assetTokenID: tokenID, price: price, rentalPeriodSeconds: rentListingRef.rentalPeriodSeconds, seller: self.owner?.address)
233 } else {
234 assert(rentalPeriodSeconds != nil, message: "Rental period must be supplied for new listing")
235
236 let oldRentListing <- self.rentListings[tokenID] <- create RentListing(rentalPeriodSeconds: rentalPeriodSeconds!)
237 destroy oldRentListing
238
239 emit AssetListedForRent(assetTokenID: tokenID, price: price, rentalPeriodSeconds: rentalPeriodSeconds!, seller: self.owner?.address)
240 }
241 }
242
243 /// batchListForTransfer lists an array of NFTs for transfer in this transfer collection at the specified price, or updates existing listings
244 ///
245 /// Parameters: tokenIDs: The array of NFT IDs to be put up for transfer
246 /// salePrice: The sale price of the NFT(This is just returned back as an event)
247 /// auctionPrice: The auction price of the NFT(This is just returned back as an event)
248 /// auctionStartTimestamp: The auction start timestamp
249 /// auctionPeriodSeconds: The period for which auction will last
250 access(contract) fun batchListForTransfer(tokenIDs: [UInt64], salePrice: UFix64?, auctionPrice: UFix64?, auctionStartTimestamp: UFix64?, auctionPeriodSeconds: UFix64?) {
251
252 let existingTransferListings: [UInt64] = []
253 let nonExistingTransferListings: [UInt64] = []
254
255 for tokenID in tokenIDs {
256 if (!self.ownerCollection.borrow()!.idExists(id: tokenID)) {
257 panic("Asset does not exist in the owner's collection: ".concat(tokenID.toString()))
258 }
259
260 if self.transferListings.containsKey(tokenID) {
261 existingTransferListings.append(tokenID)
262 } else {
263 let oldTransferListing <- self.transferListings[tokenID] <- create TransferListing()
264 destroy oldTransferListing
265
266 nonExistingTransferListings.append(tokenID)
267 }
268 }
269
270 if (nonExistingTransferListings.length > 0) {
271 emit AssetBatchListedForTransfer(assetTokenIDs: nonExistingTransferListings, salePrice: salePrice, auctionPrice: auctionPrice, auctionStartTimestamp: auctionStartTimestamp, auctionPeriodSeconds: auctionPeriodSeconds, seller: self.owner?.address)
272 }
273
274 if (existingTransferListings.length > 0) {
275 emit AssetBatchTransferListingChanged(assetTokenIDs: existingTransferListings, salePrice: salePrice, auctionPrice: auctionPrice, auctionStartTimestamp: auctionStartTimestamp, auctionPeriodSeconds: auctionPeriodSeconds, seller: self.owner?.address)
276 }
277 }
278
279 /// batchListForRent lists an array of NFTs for rent in this sale collection at the specified price and rental period, or updates existing listings
280 ///
281 /// Parameters: tokenIDs: The array of NFT IDs to be put up for rent
282 /// price: The rent price of the NFT(This is just returned back as an event)
283 /// rentalPeriodSeconds: The rental period (in seconds)
284 access(contract) fun batchListForRent(tokenIDs: [UInt64], price: UFix64?, rentalPeriodSeconds: UFix64?) {
285
286 let existingRentListings: [UInt64] = []
287 let nonExistingRentListings: [UInt64] = []
288
289 for tokenID in tokenIDs {
290 if (!self.ownerCollection.borrow()!.idExists(id: tokenID)) {
291 panic("Asset does not exist in the owner's collection: ".concat(tokenID.toString()))
292 }
293
294 if let rentListing <- self.rentListings.remove(key: tokenID) {
295 if(rentalPeriodSeconds != nil) {
296 rentListing.setRentalPeriodSeconds(seconds: rentalPeriodSeconds!)
297 }
298
299 let oldRentListing <- self.rentListings[tokenID] <- rentListing
300 destroy oldRentListing
301
302 let rentListingRef = (&self.rentListings[tokenID] as &RentListing?)!
303
304 existingRentListings.append(tokenID)
305 } else {
306 assert(rentalPeriodSeconds != nil, message: "Rental period must be supplied for new listing")
307
308 let oldRentListing <- self.rentListings[tokenID] <- create RentListing(rentalPeriodSeconds: rentalPeriodSeconds!)
309 destroy oldRentListing
310
311 nonExistingRentListings.append(tokenID)
312 }
313 }
314
315 if (nonExistingRentListings.length > 0) {
316 emit AssetBatchListedForRent(assetTokenIDs: nonExistingRentListings, price: price, rentalPeriodSeconds: rentalPeriodSeconds!, seller: self.owner?.address)
317 }
318
319 if (existingRentListings.length > 0) {
320 emit AssetBatchRentListingChanged(assetTokenIDs: existingRentListings, price: price, rentalPeriodSeconds: rentalPeriodSeconds!, seller: self.owner?.address)
321 }
322 }
323
324 /// cancelTransfer cancels an asset transfer and clears its price
325 ///
326 /// Parameters: tokenID: the ID of the token to remove from the transfer
327 access(contract) fun cancelTransfer(tokenID: UInt64) {
328 pre {
329 self.transferListings[tokenID] != nil:
330 "Asset not listed for transfer"
331 }
332
333 /// Remove the listing from the listing dictionary
334 let oldTransferListing <- self.transferListings.remove(key: tokenID)
335 destroy oldTransferListing
336
337 /// Emit the event for delisting a moment from the Transfer
338 emit AssetDelistedForTransfer(assetTokenID: tokenID, owner: self.owner?.address)
339 }
340
341 /// cancelRent cancels an asset rent and clears its price
342 ///
343 /// Parameters: tokenID: the ID of the token to remove from the sale
344 access(contract) fun cancelRent(tokenID: UInt64) {
345 pre {
346 self.rentListings[tokenID] != nil:
347 "Asset not listed for rent"
348 }
349
350 /// Remove the listing from the listings dictionary
351 let oldRentListing <- self.rentListings.remove(key: tokenID)
352 destroy oldRentListing
353
354 /// Emit the event for delisting an asset for rent
355 emit AssetDelistedForRent(assetTokenID: tokenID, owner: self.owner?.address)
356 }
357
358 /// batchCancelTransfer cancels the transfer listings for the array of NFTs
359 ///
360 /// Parameters: tokenIDs: The array of NFT IDs to be removed for transfer
361 access(contract) fun batchCancelTransfer(tokenIDs: [UInt64]) {
362 for tokenID in tokenIDs {
363 if (self.transferListings[tokenID] == nil) {
364 panic("Asset not listed for transfer: ".concat(tokenID.toString()))
365 }
366
367 /// Remove the listing from the listing dictionary
368 let oldTransferListing <- self.transferListings.remove(key: tokenID)
369 destroy oldTransferListing
370 }
371
372 /// Emit the event for delisting a moment from the Transfer
373 emit AssetBatchDelistedForTransfer(assetTokenIDs: tokenIDs, owner: self.owner?.address)
374 }
375
376 /// batchCancelRent cancels the rent listings for the array of NFTs
377 ///
378 /// Parameters: tokenIDs: The array of NFT IDs to be removed for rent
379 access(contract) fun batchCancelRent(tokenIDs: [UInt64]) {
380 for tokenID in tokenIDs {
381 if (self.rentListings[tokenID] == nil) {
382 panic("Asset not listed for rent: ".concat(tokenID.toString()))
383 }
384
385 /// Remove the listing from the listings dictionary
386 let oldRentListing <- self.rentListings.remove(key: tokenID)
387 destroy oldRentListing
388 }
389
390 /// Emit the event for delisting an asset for rent
391 emit AssetBatchDelistedForRent(assetTokenIDs: tokenIDs, owner: self.owner?.address)
392 }
393
394 /// purchase lets a user send tokens to purchase an NFT that is for sale
395 /// the purchased NFT is returned to the transaction context that called it
396 ///
397 /// Parameters: tokenID: the ID of the NFT to purchase
398 /// adminAccount: Admin Account
399 /// recipientAddress: Recipient Address
400 /// price: transaction price for the transfer
401 /// paymentID
402 access(contract) fun transfer(tokenID: UInt64, adminAccount: &TrmAssetV2_1.Admin, recipientAddress: Address, price: UFix64, paymentID: String) {
403 pre {
404 self.transferListings.containsKey(tokenID):
405 "No token matching this ID for transfer!"
406
407 self.owner?.address != recipientAddress:
408 "The recipient and owner cannot be same"
409 }
410
411 let transferListingRef = (&self.transferListings[tokenID] as &TransferListing?)!
412
413 /// Remove the transfer listing
414 if let transferListing <- self.transferListings.remove(key: tokenID) {
415 destroy transferListing
416 }
417
418 /// Remove for rent listing
419 if let rentListing <- self.rentListings.remove(key: tokenID) {
420 destroy rentListing
421 }
422
423 let boughtAsset <- adminAccount.withdrawAsset(assetCollectionAddress: self.owner!.address, id: tokenID)
424
425 adminAccount.depositAsset(assetCollectionAddress: recipientAddress, token: <-boughtAsset)
426
427 emit AssetTransferred(assetTokenID: tokenID, price: price, seller: self.owner?.address, buyer: recipientAddress, paymentID: paymentID)
428 }
429
430 /// rent lets a user send tokens to rent an NFT that is for rent
431 /// the newly minted rent NFT is returned to the transaction context that called it
432 ///
433 /// Parameters: tokenID: the ID of the NFT to purchase
434 /// price: transaction price for the rent
435 /// recipient: Recipient Collection to receive Rent Token
436 access(contract) fun rent(tokenID: UInt64, price: UFix64, recipient: Capability<&{TrmRentV2_1.CollectionPublic}>, paymentID: String): UInt64 {
437 pre {
438 self.rentListings.containsKey(tokenID):
439 "No token matching this ID for rent!"
440
441 recipient.check():
442 "Invalid receiver capability"
443
444 recipient.borrow()!.owner?.address != self.ownerCollection.borrow()!.owner?.address:
445 "The recipient and owner cannot be same"
446 }
447
448 let rentListingRef = (&self.rentListings[tokenID] as &RentListing?)!
449
450 /// Read the rental period for the token
451 let rentalPeriodSeconds = rentListingRef.rentalPeriodSeconds
452
453 let ownerCollectionRef = self.ownerCollection.borrow()!
454
455 assert(ownerCollectionRef.idExists(id: tokenID) == true, message: "Specified token ID not found in owner collection")
456
457 let expiry = rentalPeriodSeconds + getCurrentBlock().timestamp
458
459 let minterRef = TrmMarketV2_1_1.minterCapability.borrow()!
460
461 let kID = ownerCollectionRef.getKID(id: tokenID)
462 let assetName = ownerCollectionRef.getAssetName(id: tokenID)
463 let assetDescription = ownerCollectionRef.getAssetDescription(id: tokenID)
464 let assetURL = ownerCollectionRef.getAssetURL(id: tokenID)
465 let assetThumbnailURL = ownerCollectionRef.getAssetThumbnailURL(id: tokenID)
466 // let assetMetadata = ownerCollectionRef.getAssetMetadata(id: tokenID)
467 let assetMetadata: {String: String} = {}
468
469 let rentTokenID = minterRef.mintNFT(assetTokenID: tokenID, kID: kID, assetName: assetName, assetDescription: assetDescription, assetURL: assetURL, assetThumbnailURL: assetThumbnailURL, assetMetadata: assetMetadata, expiryTimestamp: expiry, recipient: recipient.borrow()!)
470
471 emit AssetRented(assetTokenID: tokenID, rentID: rentTokenID, price: price, expiryTimestamp: expiry, assetName: assetName, assetDescription: assetDescription, assetURL: assetURL, assetThumbnailURL: assetThumbnailURL, assetMetadata: assetMetadata, kID: kID, seller: self.owner?.address, buyer: recipient.borrow()!.owner?.address, rentalPeriodSeconds: rentalPeriodSeconds, paymentID: paymentID)
472
473 return rentTokenID
474 }
475
476 /// getTransferListing returns the transfer listing of a specific token in the collection
477 ///
478 /// Parameters: tokenID: The ID of the NFT whose listing to get
479 ///
480 /// Returns: TransferListing: The transfer listing of the token including price
481 pub fun getTransferListing(tokenID: UInt64): &TransferListing? {
482 if self.transferListings.containsKey(tokenID) {
483 return &self.transferListings[tokenID] as &TransferListing?
484 }
485 return nil
486 }
487
488 /// getRentListing returns the rent listing of a specific token in the collection
489 ///
490 /// Parameters: tokenID: The ID of the NFT whose listing to get
491 ///
492 /// Returns: RentListing: The rent listing of the token including price, rental period
493 pub fun getRentListing(tokenID: UInt64): &RentListing? {
494 if self.rentListings.containsKey(tokenID) {
495 return &self.rentListings[tokenID] as &RentListing?
496 }
497 return nil
498 }
499
500 /// getTransferIDs returns an array of token IDs that are for transfer
501 pub fun getTransferIDs(): [UInt64] {
502 return self.transferListings.keys
503 }
504
505 /// getRentIDs returns an array of token IDs that are for sale
506 pub fun getRentIDs(): [UInt64] {
507 return self.rentListings.keys
508 }
509
510 /// borrowAsset Returns a borrowed reference to an Asset in the Collection so that the caller can read data from it
511 ///
512 /// Parameters: id: The ID of the token to borrow a reference to
513 ///
514 /// Returns: &TrmAssetV2_1.NFT? Optional reference to a token for transfer so that the caller can read its data
515 pub fun borrowAsset(id: UInt64): &TrmAssetV2_1.NFT? {
516 /// first check this collection
517 if self.transferListings[id] != nil || self.rentListings[id] != nil {
518 let ref = self.ownerCollection.borrow()!.borrowAsset(id: id)
519 return ref
520 }
521 return nil
522 }
523 }
524
525 /// createCollection returns a new collection resource to the caller
526 pub fun createSaleCollection(ownerCollection: Capability<&TrmAssetV2_1.Collection>): @SaleCollection {
527
528 return <- create SaleCollection(ownerCollection: ownerCollection)
529 }
530
531 /// Admin is a special authorization resource that
532 /// allows the admin to perform important functions
533 pub resource Admin {
534
535 pub fun listForTransfer(
536 saleCollectionAddress: Address,
537 tokenID: UInt64,
538 salePrice: UFix64?,
539 auctionPrice: UFix64?,
540 auctionStartTimestamp: UFix64?,
541 auctionPeriodSeconds: UFix64?
542 ) {
543 let saleCollectionCapability = getAccount(saleCollectionAddress).getCapability<&TrmMarketV2_1_1.SaleCollection{TrmMarketV2_1_1.SalePublic}>(
544 TrmMarketV2_1_1.marketPublicPath
545 ).borrow()
546 ?? panic("Could not borrow sale collection capability from provided sale collection address")
547
548 saleCollectionCapability.listForTransfer(tokenID: tokenID, salePrice: salePrice, auctionPrice: auctionPrice, auctionStartTimestamp: auctionStartTimestamp, auctionPeriodSeconds: auctionPeriodSeconds)
549 }
550
551 pub fun listForRent(
552 saleCollectionAddress: Address,
553 tokenID: UInt64,
554 price: UFix64?,
555 rentalPeriodSeconds: UFix64?
556 ) {
557 let saleCollectionCapability = getAccount(saleCollectionAddress).getCapability<&TrmMarketV2_1_1.SaleCollection{TrmMarketV2_1_1.SalePublic}>(
558 TrmMarketV2_1_1.marketPublicPath
559 ).borrow()
560 ?? panic("Could not borrow sale collection capability from provided sale collection address")
561
562 saleCollectionCapability.listForRent(tokenID: tokenID, price: price, rentalPeriodSeconds: rentalPeriodSeconds)
563 }
564
565 pub fun batchListForTransfer(
566 saleCollectionAddress: Address,
567 tokenIDs: [UInt64],
568 salePrice: UFix64?,
569 auctionPrice: UFix64?,
570 auctionStartTimestamp: UFix64?,
571 auctionPeriodSeconds: UFix64?
572 ) {
573 let saleCollectionCapability = getAccount(saleCollectionAddress).getCapability<&TrmMarketV2_1_1.SaleCollection{TrmMarketV2_1_1.SalePublic}>(
574 TrmMarketV2_1_1.marketPublicPath
575 ).borrow()
576 ?? panic("Could not borrow sale collection capability from provided sale collection address")
577
578 saleCollectionCapability.batchListForTransfer(tokenIDs: tokenIDs, salePrice: salePrice, auctionPrice: auctionPrice, auctionStartTimestamp: auctionStartTimestamp, auctionPeriodSeconds: auctionPeriodSeconds)
579 }
580
581 pub fun batchListForRent(
582 saleCollectionAddress: Address,
583 tokenIDs: [UInt64],
584 price: UFix64?,
585 rentalPeriodSeconds: UFix64?
586 ) {
587 let saleCollectionCapability = getAccount(saleCollectionAddress).getCapability<&TrmMarketV2_1_1.SaleCollection{TrmMarketV2_1_1.SalePublic}>(
588 TrmMarketV2_1_1.marketPublicPath
589 ).borrow()
590 ?? panic("Could not borrow sale collection capability from provided sale collection address")
591
592 saleCollectionCapability.batchListForRent(tokenIDs: tokenIDs, price: price, rentalPeriodSeconds: rentalPeriodSeconds)
593 }
594
595 pub fun cancelTransfer(
596 saleCollectionAddress: Address,
597 tokenID: UInt64
598 ) {
599 let saleCollectionCapability = getAccount(saleCollectionAddress).getCapability<&TrmMarketV2_1_1.SaleCollection{TrmMarketV2_1_1.SalePublic}>(
600 TrmMarketV2_1_1.marketPublicPath
601 ).borrow()
602 ?? panic("Could not borrow sale collection capability from provided sale collection address")
603
604 saleCollectionCapability.cancelTransfer(tokenID: tokenID)
605 }
606
607 pub fun cancelRent(
608 saleCollectionAddress: Address,
609 tokenID: UInt64
610 ) {
611 let saleCollectionCapability = getAccount(saleCollectionAddress).getCapability<&TrmMarketV2_1_1.SaleCollection{TrmMarketV2_1_1.SalePublic}>(
612 TrmMarketV2_1_1.marketPublicPath
613 ).borrow()
614 ?? panic("Could not borrow sale collection capability from provided sale collection address")
615
616 saleCollectionCapability.cancelRent(tokenID: tokenID)
617 }
618
619 pub fun batchCancelTransfer(
620 saleCollectionAddress: Address,
621 tokenIDs: [UInt64]
622 ) {
623 let saleCollectionCapability = getAccount(saleCollectionAddress).getCapability<&TrmMarketV2_1_1.SaleCollection{TrmMarketV2_1_1.SalePublic}>(
624 TrmMarketV2_1_1.marketPublicPath
625 ).borrow()
626 ?? panic("Could not borrow sale collection capability from provided sale collection address")
627
628 saleCollectionCapability.batchCancelTransfer(tokenIDs: tokenIDs)
629 }
630
631 pub fun batchCancelRent(
632 saleCollectionAddress: Address,
633 tokenIDs: [UInt64]
634 ) {
635 let saleCollectionCapability = getAccount(saleCollectionAddress).getCapability<&TrmMarketV2_1_1.SaleCollection{TrmMarketV2_1_1.SalePublic}>(
636 TrmMarketV2_1_1.marketPublicPath
637 ).borrow()
638 ?? panic("Could not borrow sale collection capability from provided sale collection address")
639
640 saleCollectionCapability.batchCancelRent(tokenIDs: tokenIDs)
641 }
642
643 pub fun transfer(
644 saleCollectionAddress: Address,
645 tokenID: UInt64,
646 assetAdminResource: &TrmAssetV2_1.Admin,
647 recipientAddress: Address,
648 price: UFix64,
649 paymentID: String
650 ) {
651 let saleCollectionCapability = getAccount(saleCollectionAddress).getCapability<&TrmMarketV2_1_1.SaleCollection{TrmMarketV2_1_1.SalePublic}>(
652 TrmMarketV2_1_1.marketPublicPath
653 ).borrow()
654 ?? panic("Could not borrow sale collection capability from provided sale collection address")
655
656 saleCollectionCapability.transfer(tokenID: tokenID, adminAccount: assetAdminResource, recipientAddress: recipientAddress, price: price, paymentID: paymentID)
657 }
658
659 pub fun rent(
660 saleCollectionAddress: Address,
661 tokenID: UInt64,
662 price: UFix64,
663 recipient: Capability<&{TrmRentV2_1.CollectionPublic}>,
664 paymentID: String
665 ): UInt64 {
666 let saleCollectionCapability = getAccount(saleCollectionAddress).getCapability<&TrmMarketV2_1_1.SaleCollection{TrmMarketV2_1_1.SalePublic}>(
667 TrmMarketV2_1_1.marketPublicPath
668 ).borrow()
669 ?? panic("Could not borrow sale collection capability from provided sale collection address")
670
671 return saleCollectionCapability.rent(tokenID: tokenID, price: price, recipient: recipient, paymentID: paymentID)
672 }
673 }
674
675 init() {
676 // Settings paths
677 self.marketStoragePath = /storage/TrmMarketV2_1_1SaleCollection
678 self.marketPublicPath = /public/TrmMarketV2_1_1SaleCollection
679 self.marketPrivatePath = /private/TrmMarketV2_1_1SaleCollection
680 self.adminStoragePath = /storage/TrmMarketV2_1_1Admin
681
682 /// First, check to see if a admin resource already exists
683 if self.account.type(at: self.adminStoragePath) == nil {
684
685 /// Put the Admin in storage
686 self.account.save<@Admin>(<- create Admin(), to: self.adminStoragePath)
687 }
688
689 /// obtain Admin's private rent minter capability
690 self.minterCapability = self.account.getCapability<&TrmRentV2_1.Minter>(TrmRentV2_1.minterPrivatePath)
691
692 emit ContractInitialized()
693 }
694}
695