MarketplaceSEALED
░$*$◆^$%@╲~!??▪●◇▪!■○?○%◆^◇○!◇◆$█◇^^@○▫▫?@╳■□◆▓&▒╱●╲●◆█╳●░$░$!◆^
Transaction ID
Transaction Summary
MarketplaceCalled FungibleToken, NonFungibleToken, DapperUtilityCoin +5 more
Script Arguments
0saleItemIDUInt64
257285723428231
1saleItemPriceUFix64
50.00000000
2expiryUInt64
33328955331
Cadence Script
1import FungibleToken from 0xf233dcee88fe0abe
2import NonFungibleToken from 0x1d7e57aa55817448
3import DapperUtilityCoin from 0xead892083b3e2c6c
4import PackNFT from 0xe4cf4bdc1751c65d
5import IPackNFT from 0x18ddf0823a55a0ee
6import NFTStorefrontV2 from 0x4eb8a10cb9f87357
7import MetadataViews from 0x1d7e57aa55817448
8import TokenForwarding from 0xe544175ee0461c4b
9
10// This transaction facilitates the listing of an NFT with the StorefrontV2 contract
11//
12// Collection Identifier: PackNFT
13// Vault Identifier: duc
14//
15// Version: 0.1.1
16
17/// ''saleItemID'' - ID of the NFT that is put on sale by the seller.
18/// ''saleItemPrice'' - Amount of tokens (FT) buyer needs to pay for the purchase of listed NFT.
19/// ''expiry'' - Unix timestamp at which created listing become expired.
20
21transaction(saleItemID: UInt64, saleItemPrice: UFix64, expiry: UInt64) {
22 var ftReceiver: Capability<&{FungibleToken.Receiver}>?
23 let nftProvider: Capability<auth(NonFungibleToken.Withdraw) &{NonFungibleToken.Collection}>?
24 let storefront: auth(NFTStorefrontV2.CreateListing) &NFTStorefrontV2.Storefront
25 var saleCuts: [NFTStorefrontV2.SaleCut]
26 var marketplacesCapability: [Capability<&{FungibleToken.Receiver}>]
27
28 /// ''customID'' - Optional string to represent identifier of the dapp.
29 let customID: String
30 /// ''commissionAmount'' - Commission amount that will be taken away by the purchase facilitator i.e marketplacesAddress.
31 let commissionAmount: UFix64
32 /// ''marketplacesAddress'' - List of addresses that are allowed to get the commission.
33 let marketplaceAddress: [Address]
34 // we only ever want to use DapperUtilityCoin
35 let universalDucReceiver: Address
36
37 prepare(acct: auth(Storage, Capabilities) &Account) {
38 /// ''customID'' - Optional string to represent identifier of the dapp.
39 self.customID = "DAPPER_MARKETPLACE"
40 /// ''commissionAmount'' - Commission amount that will be taken away by the purchase facilitator i.e marketplacesAddress.
41 self.commissionAmount = 0.0
42 /// ''marketplacesAddress'' - List of addresses that are allowed to get the commission.
43 self.marketplaceAddress = [0xe4cf4bdc1751c65d]
44 // we only ever want to use DapperUtilityCoin
45 self.universalDucReceiver = 0xead892083b3e2c6c
46
47 self.saleCuts = []
48 self.marketplacesCapability = []
49
50 // ************************* Handling of DUC Recevier *************************** //
51
52 // Fetch the capability of the universal DUC receiver
53 let recipient = getAccount(self.universalDucReceiver).capabilities.get<&{FungibleToken.Receiver}>(/public/dapperUtilityCoinReceiver)!
54 assert(recipient.borrow() != nil, message: "Missing or mis-typed Fungible Token receiver for the DUC recipient")
55
56 self.ftReceiver = acct.capabilities.get<&{FungibleToken.Receiver}>(/public/dapperUtilityCoinReceiver)
57
58 // Validate the marketplaces capability before submiting to ''createListing''.
59 for mp in self.marketplaceAddress {
60 let marketplaceReceiver = getAccount(mp).capabilities.get<&{FungibleToken.Receiver}>(/public/dapperUtilityCoinReceiver)
61 assert(marketplaceReceiver.borrow() != nil && marketplaceReceiver.borrow()!.isInstance(Type<@TokenForwarding.Forwarder>()), message: "Marketplaces does not possess the valid receiver type for DUC")
62 self.marketplacesCapability.append(marketplaceReceiver!)
63 }
64
65 // *************************** Seller account interactions *************************** //
66
67 // This checks for the public capability
68 if !acct.capabilities.get<&PackNFT.Collection>(PackNFT.CollectionPublicPath)!.check() {
69 acct.capabilities.unpublish(PackNFT.CollectionPublicPath)
70 acct.capabilities.publish(
71 acct.capabilities.storage.issue<&PackNFT.Collection>(PackNFT.CollectionStoragePath),
72 at: PackNFT.CollectionPublicPath
73 )
74 }
75
76 let PrivateCollectionPath = /storage/AllDayPackNFTCollectionProviderForNFTStorefront
77
78 // Temporary variable to handle capability assignment
79 var provider: Capability<auth(NonFungibleToken.Withdraw) &{NonFungibleToken.Collection}>? =
80 acct.storage.copy<Capability<auth(NonFungibleToken.Withdraw) &{NonFungibleToken.Collection}>>(from: PrivateCollectionPath)
81
82 if provider == nil {
83 provider = acct.capabilities.storage.issue<auth(NonFungibleToken.Withdraw) &{NonFungibleToken.Collection}>(PackNFT.CollectionStoragePath)
84 acct.capabilities.storage.getController(byCapabilityID: provider!.id)!.setTag("AllDayPackNFTCollectionProviderForNFTStorefront")
85 // Save the capability to the account storage
86 acct.storage.save(provider!, to: PrivateCollectionPath)
87 }
88
89 self.nftProvider = provider
90 assert(self.nftProvider?.borrow() != nil, message: "Missing or mis-typed PackNFT.Collection provider")
91
92 let collectionRef = acct
93 .capabilities.borrow<&PackNFT.Collection>(PackNFT.CollectionPublicPath)
94 ?? panic("Could not borrow a reference to the collection")
95
96 var totalRoyaltyCut = 0.0
97 let effectiveSaleItemPrice = saleItemPrice - self.commissionAmount
98
99 let nft = collectionRef.borrowNFT(saleItemID)!
100 // Check whether the NFT implements the MetadataResolver or not.
101 if nft.getViews().contains(Type<MetadataViews.Royalties>()) {
102 let royaltiesRef = nft.resolveView(Type<MetadataViews.Royalties>()) ?? panic("Unable to retrieve the royalties")
103 let royalties = (royaltiesRef as! MetadataViews.Royalties).getRoyalties()
104 for royalty in royalties {
105 let royaltyReceiver = royalty.receiver
106 assert(royaltyReceiver.borrow() != nil && royaltyReceiver.borrow()!.isInstance(Type<@TokenForwarding.Forwarder>()), message: "Royalty receiver does not have a valid receiver type")
107 self.saleCuts.append(NFTStorefrontV2.SaleCut(receiver: royalty.receiver, amount: royalty.cut * effectiveSaleItemPrice))
108 totalRoyaltyCut = totalRoyaltyCut + royalty.cut * effectiveSaleItemPrice
109 }
110 }
111
112 // Append the cut for the seller.
113 self.saleCuts.append(NFTStorefrontV2.SaleCut(
114 receiver: self.ftReceiver!,
115 amount: effectiveSaleItemPrice - totalRoyaltyCut
116 ))
117
118 if acct.storage.borrow<&NFTStorefrontV2.Storefront>(from: NFTStorefrontV2.StorefrontStoragePath) == nil {
119 // Create a new empty Storefront
120 let storefront <- NFTStorefrontV2.createStorefront() as! @NFTStorefrontV2.Storefront
121 // save it to the account
122 acct.storage.save(<-storefront, to: NFTStorefrontV2.StorefrontStoragePath)
123 // create a public capability for the Storefront
124 acct.capabilities.publish(
125 acct.capabilities.storage.issue<&NFTStorefrontV2.Storefront>(NFTStorefrontV2.StorefrontStoragePath),
126 at: NFTStorefrontV2.StorefrontPublicPath
127 )
128 }
129 self.storefront = acct.storage.borrow<auth(NFTStorefrontV2.CreateListing) &NFTStorefrontV2.Storefront>(from: NFTStorefrontV2.StorefrontStoragePath)!
130 }
131
132 execute {
133 // Create listing
134 self.storefront.createListing(
135 nftProviderCapability: self.nftProvider!,
136 nftType: Type<@PackNFT.NFT>(),
137 nftID: saleItemID,
138 salePaymentVaultType: Type<@DapperUtilityCoin.Vault>(),
139 saleCuts: self.saleCuts,
140 marketplacesCapability: self.marketplacesCapability.length == 0 ? nil : self.marketplacesCapability,
141 customID: self.customID,
142 commissionAmount: self.commissionAmount,
143 expiry: expiry
144 )
145 }
146}