TransactionSEALED

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

Transaction ID

Timestamp

Feb 24, 2026, 12:56:36 AM UTC
4d ago

Block Height

143,217,030

Computation

0

Execution Fee

0.00274 FLOW

Transaction Summary

Contract Call

Called OffersV2, DapperOffersV2, TopShot +4 more

Script Arguments

0amountUFix64
184.00000000
1royalties{Address
{
  "0xfaf0cc52c6e3acaf": "9.20000000"
}
2offerParamsString{String
{
  "playId": "81",
  "setId": "8",
  "playUuid": "6aaed757-2d22-44c7-8f64-e7a46ca0c13e",
  "setUuid": "c561f66b-5bd8-451c-8686-156073c3fb69",
  "resolver": "1"
}

Cadence Script

1import OffersV2 from 0xb8ea91944fd51c43
2import DapperOffersV2 from 0xb8ea91944fd51c43
3import TopShot from 0x0b2a3299cc857e29
4import NonFungibleToken from 0x1d7e57aa55817448
5import FungibleToken from 0xf233dcee88fe0abe
6import DapperUtilityCoin from 0xead892083b3e2c6c
7import Resolver from 0xb8ea91944fd51c43
8transaction(amount: UFix64, royalties: {Address:UFix64}, offerParamsString: {String:String}) {
9    var nftReceiver: Capability<&{NonFungibleToken.CollectionPublic}>?
10    let dapperOffer: auth(DapperOffersV2.Manager) &DapperOffersV2.DapperOffer
11    var ducVaultRef: Capability<auth(FungibleToken.Withdraw) &{FungibleToken.Vault}>
12    let resolverCapability: Capability<&{Resolver.ResolverPublic}>
13    var proxyManagerCap: Capability<auth(DapperOffersV2.ProxyManager) &DapperOffersV2.DapperOffer>
14    var ROYALITY_ADDRESS: Address
15    var ROYALITY_PERCENT: UFix64
16    prepare(signer: auth(Storage, Capabilities) &Account, dapper: auth(Storage, Capabilities) &Account) {
17        // Link the NFT collection
18        if signer.storage.borrow<&TopShot.Collection>(from: /storage/MomentCollection) == nil {
19            let collection <- TopShot.createEmptyCollection(nftType: Type<@TopShot.NFT>())
20            signer.storage.save(<-collection, to: /storage/MomentCollection)
21            signer.capabilities.unpublish(/public/MomentCollection)
22            signer.capabilities.publish(
23			    signer.capabilities.storage.issue<&TopShot.Collection>(/storage/MomentCollection),
24			    at: /public/MomentCollection
25		    )
26        }
27        self.nftReceiver = signer.capabilities.get<&{NonFungibleToken.CollectionPublic}>(/public/MomentCollection)
28        if self.nftReceiver == nil || !self.nftReceiver!.check() {
29            signer.capabilities.unpublish(/public/MomentCollection)
30            signer.capabilities.publish(
31                signer.capabilities.storage.issue<&{NonFungibleToken.CollectionPublic}>(/storage/MomentCollection),
32                at: /public/MomentCollection
33            )
34            self.nftReceiver = signer.capabilities.get<&{NonFungibleToken.CollectionPublic}>(/public/MomentCollection)
35        }
36        // Link the DapperOffer resource
37        if signer.storage.borrow<&DapperOffersV2.DapperOffer>(from: DapperOffersV2.DapperOffersStoragePath) == nil {
38            let dapperOffer <- DapperOffersV2.createDapperOffer() as! @DapperOffersV2.DapperOffer
39            signer.storage.save(<-dapperOffer, to: DapperOffersV2.DapperOffersStoragePath)
40            signer.capabilities.publish(
41                signer.capabilities.storage.issue<&DapperOffersV2.DapperOffer>(DapperOffersV2.DapperOffersStoragePath),
42                at: DapperOffersV2.DapperOffersPublicPath
43            )
44        }
45        // DapperOfferProxyManager Setup
46        if dapper.storage.borrow<&DapperOffersV2.DapperOffer>(from: DapperOffersV2.DapperOffersStoragePath) == nil {
47            let dapperOffer <- DapperOffersV2.createDapperOffer() as! @DapperOffersV2.DapperOffer
48            dapper.storage.save(<-dapperOffer, to: DapperOffersV2.DapperOffersStoragePath)
49            dapper.capabilities.publish(
50                dapper.capabilities.storage.issue<&DapperOffersV2.DapperOffer>(DapperOffersV2.DapperOffersStoragePath),
51                at: DapperOffersV2.DapperOffersPublicPath
52            )
53        }
54        // Setup Proxy Cancel for Dapper
55        let capabilityReceiver = dapper.capabilities.borrow
56            <&DapperOffersV2.DapperOffer>
57            (/public/DapperOffersV2) ?? panic("Could not borrow capability receiver reference")
58       
59        let dapperOfferProxyManagerCapPath = /storage/DapperOfferProxyManagerCapability
60        var dapperOfferProxyManagerCap = signer.storage.copy<Capability<auth(DapperOffersV2.ProxyManager) &DapperOffersV2.DapperOffer>>(from: dapperOfferProxyManagerCapPath)
61        if dapperOfferProxyManagerCap == nil || !dapperOfferProxyManagerCap!.check() {
62            self.proxyManagerCap = signer.capabilities.storage.issue<auth(DapperOffersV2.ProxyManager) &DapperOffersV2.DapperOffer>(DapperOffersV2.DapperOffersStoragePath)
63            // save capability to storage
64            signer.capabilities.storage.getController(byCapabilityID: self.proxyManagerCap.id)!.setTag("DapperOfferProxyManagerCap")
65            signer.storage.save(
66                self.proxyManagerCap,
67                to: dapperOfferProxyManagerCapPath
68            )
69        } else {
70            self.proxyManagerCap = dapperOfferProxyManagerCap!
71        }
72        capabilityReceiver.addProxyCapability(account: signer.address, cap: self.proxyManagerCap)
73        // Setup Proxy Cancel for Collection Minter
74        let minter = getAccount(0xe1f2a091f7bb5245)
75        let capabilityReceiverCollectionMinter = minter.capabilities.borrow
76            <&DapperOffersV2.DapperOffer>
77            (/public/DapperOffersV2) ?? panic("Could not borrow capability receiver reference")
78        capabilityReceiverCollectionMinter.addProxyCapability(account: signer.address, cap: self.proxyManagerCap)
79        // Get the capability to the offer creators NFT collection
80        self.nftReceiver = signer.capabilities.get<&{NonFungibleToken.CollectionPublic}>(/public/MomentCollection)
81        self.dapperOffer = signer.storage.borrow<auth(DapperOffersV2.Manager) &DapperOffersV2.DapperOffer>(from: DapperOffersV2.DapperOffersStoragePath)
82            ?? panic("Missing or mis-typed DapperOffersV2.DapperOffer")
83        let ducWithdrawCapPath = /storage/DUCWithdrawCapabilityForOffers
84        var ducWithdrawCap = dapper.storage.copy<Capability<auth(FungibleToken.Withdraw) &{FungibleToken.Vault}>>(from: ducWithdrawCapPath)
85        if ducWithdrawCap == nil || !ducWithdrawCap!.check() {
86            self.ducVaultRef = dapper.capabilities.storage.issue<auth(FungibleToken.Withdraw) &{FungibleToken.Vault}>(/storage/dapperUtilityCoinVault)
87            // save capability to storage
88            dapper.capabilities.storage.getController(byCapabilityID: self.ducVaultRef.id)!.setTag("OffersDUCWithdrawCap")
89            dapper.storage.save(
90                self.ducVaultRef,
91                to: ducWithdrawCapPath
92            )
93        } else{
94            self.ducVaultRef = ducWithdrawCap!
95        }
96        // Validate marketplace royalties
97        self.ROYALITY_ADDRESS = 0xfaf0cc52c6e3acaf
98        self.ROYALITY_PERCENT = 0.05000000
99        assert(royalties[self.ROYALITY_ADDRESS] == self.ROYALITY_PERCENT * amount, message: "Missing or mis-typed royalty information for marketplace")
100        assert(royalties.keys.length == 1, message: "please provide only one royalty address")
101        // Validate offerParamsString and resolver for type TopShotEdition
102        assert(offerParamsString.containsKey("playId"), message: "playId missing from offerParamsString")
103        assert(offerParamsString.containsKey("setId"), message: "setId missing from offerParamsString")
104        assert(offerParamsString.containsKey("resolver"), message: "resolver missing from offerParamsString")
105        assert(offerParamsString["resolver"] == Resolver.ResolverType.TopShotEdition.rawValue.toString(), message: "Invalid resolver")
106        // Setup and link offer Resolver
107        if signer.storage.borrow<&Resolver.OfferResolver>(from: /storage/OfferResolver) == nil {
108            let resolver <- Resolver.createResolver()
109            signer.storage.save(<-resolver, to: /storage/OfferResolver)
110            signer.capabilities.publish(
111                signer.capabilities.storage.issue<&Resolver.OfferResolver>(/storage/OfferResolver),
112                at: /public/OfferResolver
113			)
114        }
115        self.resolverCapability = signer.capabilities.get<&{Resolver.ResolverPublic}>(/public/OfferResolver)!
116    }
117    execute {
118        var royaltysList: [OffersV2.Royalty] = []
119        let keys = royalties.keys
120        for key in keys {
121            royaltysList.append(OffersV2.Royalty(
122                receiver: getAccount(key).capabilities.get<&{FungibleToken.Receiver}>(/public/dapperUtilityCoinReceiver)!,
123                amount: royalties[key]!
124            ))
125        }
126        offerParamsString.insert(key: "typeId", "Type<@TopShot.NFT>()")
127
128        // Set offer type based on whether subeditionId is present
129        // Backend relies on this to identify and process subedition offers
130        if offerParamsString.containsKey("subeditionId") {
131            offerParamsString.insert(key: "_type", "TopShotSubedition")
132        } else {
133            offerParamsString.insert(key: "_type", "TopShotEdition")
134        }
135
136        self.dapperOffer.createOffer(
137            vaultRefCapability: self.ducVaultRef,
138            nftReceiverCapability: self.nftReceiver!,
139            nftType: Type<@TopShot.NFT>(),
140            amount: amount,
141            royalties: royaltysList,
142            offerParamsString: offerParamsString,
143            offerParamsUFix64: {},
144            offerParamsUInt64: {},
145            resolverCapability: self.resolverCapability
146        )
147    }
148}