TransactionSEALED

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

Transaction ID

Timestamp

Sep 05, 2024, 12:47:02 PM UTC
1y ago

Block Height

86,041,824

Computation

0

Execution Fee

0.000001 FLOW

Proposerseq:540 key:6

Authorizers

1

Transaction Summary

Contract Call

Called FungibleToken, NonFungibleToken, DapperUtilityCoin +4 more

Script Arguments

0saleItemIDUInt64
946516495
1saleItemPriceUFix64
254.00000000
2expiryUInt64
33282443282

Cadence Script

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