MarketplaceSEALED

□&╱◇&◆▒╳░◇█@╲░╲●◇█▒#~■▓!╲!▒%!@$●▒*▫╱█▒▪*#◆?%#●?!!▫#╳□%~◇■~●░▓@░▓

Transaction ID

Timestamp

Apr 12, 2024, 11:36:09 PM UTC
1y ago

Block Height

76,026,330

Computation

0

Execution Fee

0.00001457 FLOW

Proposerseq:5690 key:7

Authorizers

1

Transaction Summary

UpdatingMarketplace

Called FungibleToken, NonFungibleToken, DapperUtilityCoin +5 more

Script Arguments

Copy:
0saleItemIDUInt64
130841884110515
1saleItemPriceUFix64
7.00000000
2expiryUInt64
33269873762

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<&AnyResource{FungibleToken.Receiver}>
23    let nftProvider: Capability<&AnyResource{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic}>
24    let storefront: &NFTStorefrontV2.Storefront
25    var saleCuts: [NFTStorefrontV2.SaleCut]
26    var marketplacesCapability: [Capability<&AnyResource{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: AuthAccount) {
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        let PrivateCollectionPath = /private/AllDayPackNFTCollectionProviderForNFTStorefront
50
51        // ************************* Handling of DUC Recevier *************************** //
52        
53        // Fetch the capability of the universal DUC receiver
54        let recipient = getAccount(self.universalDucReceiver).getCapability<&{FungibleToken.Receiver}>(/public/dapperUtilityCoinReceiver)
55        assert(recipient.borrow() != nil, message: "Missing or mis-typed Fungible Token receiver for the DUC recipient")
56
57        // Check whether the receiver has the capability to receive the DUC
58        self.ftReceiver = acct.getCapability<&{FungibleToken.Receiver}>(/public/dapperUtilityCoinReceiver)
59        if self.ftReceiver.borrow() == nil || !self.ftReceiver.borrow()!.isInstance(Type<@TokenForwarding.Forwarder>()) {
60            acct.unlink(/public/dapperUtilityCoinReceiver)
61            // Create the forwarder and save it to the account that is doing the forwarding
62            let vault <- TokenForwarding.createNewForwarder(recipient: recipient)
63            acct.save(<-vault, to: /storage/ducTokenForwarder)
64            // Link the new forwarding receiver capability
65            acct.link<&{FungibleToken.Receiver}>(
66                /public/dapperUtilityCoinReceiver,
67                target: /storage/ducTokenForwarder
68            )
69            self.ftReceiver = acct.getCapability<&{FungibleToken.Receiver}>(/public/dapperUtilityCoinReceiver)
70        }
71
72        // Validate the marketplaces capability before submiting to ''createListing''.
73        for mp in self.marketplaceAddress {
74            let marketplaceReceiver = getAccount(mp).getCapability<&{FungibleToken.Receiver}>(/public/dapperUtilityCoinReceiver)
75            assert(marketplaceReceiver.borrow() != nil && marketplaceReceiver.borrow()!.isInstance(Type<@TokenForwarding.Forwarder>()), message: "Marketplaces does not possess the valid receiver type for DUC")
76            self.marketplacesCapability.append(marketplaceReceiver)
77        }
78
79        // *************************** Seller account interactions  *************************** //
80
81        // This checks for the public capability
82        if !acct.getCapability<&PackNFT.Collection{IPackNFT.IPackNFTCollectionPublic}>(PackNFT.CollectionPublicPath)!.check() {
83            acct.unlink(PackNFT.CollectionPublicPath)
84            acct.link<&PackNFT.Collection{IPackNFT.IPackNFTCollectionPublic, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, MetadataViews.ResolverCollection }>(PackNFT.CollectionPublicPath, target: PackNFT.CollectionStoragePath)
85        }
86
87        // Check if the Provider capability exists or not if ''no'' then create a new link for the same.
88        if !acct.getCapability<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic}>(PrivateCollectionPath)!.check() {
89            acct.unlink(PrivateCollectionPath)
90            acct.link<&PackNFT.Collection{IPackNFT.IPackNFTCollectionPublic, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, NonFungibleToken.Provider, MetadataViews.ResolverCollection }>(PrivateCollectionPath, target: PackNFT.CollectionStoragePath)
91        }
92
93        self.nftProvider = acct.getCapability<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic}>(PrivateCollectionPath)!
94        let collectionRef = acct
95            .getCapability<&PackNFT.Collection{IPackNFT.IPackNFTCollectionPublic}>(PackNFT.CollectionPublicPath).borrow()
96            ?? panic("Could not borrow a reference to the collection")
97        
98        var totalRoyaltyCut = 0.0
99        let effectiveSaleItemPrice = saleItemPrice - self.commissionAmount
100        
101        let nft = collectionRef.borrowPackNFT(id: saleItemID)!
102        // Check whether the NFT implements the MetadataResolver or not.
103        if nft.getViews().contains(Type<MetadataViews.Royalties>()) {
104            let royaltiesRef = nft.resolveView(Type<MetadataViews.Royalties>()) ?? panic("Unable to retrieve the royalties")
105            let royalties = (royaltiesRef as! MetadataViews.Royalties).getRoyalties()
106            for royalty in royalties {
107                let royaltyReceiver = royalty.receiver
108                assert(royaltyReceiver.borrow() != nil && royaltyReceiver.borrow()!.isInstance(Type<@TokenForwarding.Forwarder>()), message: "Royalty receiver does not have a valid receiver type")
109                self.saleCuts.append(NFTStorefrontV2.SaleCut(receiver: royalty.receiver, amount: royalty.cut * effectiveSaleItemPrice))
110                totalRoyaltyCut = totalRoyaltyCut + royalty.cut * effectiveSaleItemPrice
111            }
112        }
113        
114        // Append the cut for the seller.
115        self.saleCuts.append(NFTStorefrontV2.SaleCut(
116            receiver: self.ftReceiver,
117            amount: effectiveSaleItemPrice - totalRoyaltyCut
118        ))
119        assert(self.nftProvider.borrow() != nil, message: "Missing or mis-typed PackNFT.Collection provider")
120
121        if acct.borrow<&NFTStorefrontV2.Storefront>(from: NFTStorefrontV2.StorefrontStoragePath) == nil {
122            // Create a new empty Storefront
123            let storefront <- NFTStorefrontV2.createStorefront() as! @NFTStorefrontV2.Storefront
124            // save it to the account
125            acct.save(<-storefront, to: NFTStorefrontV2.StorefrontStoragePath)
126            // create a public capability for the Storefront
127            acct.link<&NFTStorefrontV2.Storefront{NFTStorefrontV2.StorefrontPublic}>(NFTStorefrontV2.StorefrontPublicPath, target: NFTStorefrontV2.StorefrontStoragePath)
128        }
129        self.storefront = acct.borrow<&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}