TransactionSEALED

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

Transaction ID

Timestamp

Sep 23, 2025, 01:09:37 AM UTC
5mo ago

Block Height

127,123,965

Computation

0

Execution Fee

0.00002649 FLOW

Transaction Summary

Contract Call

Called Swap, Utils, MetadataViews +4 more

Script Arguments

Cadence Script

1import Swap from 0x15f55a75d7843780
2import Utils from 0x15f55a75d7843780
3import MetadataViews from 0x1d7e57aa55817448
4import NonFungibleToken from 0x1d7e57aa55817448
5import FungibleToken from 0xf233dcee88fe0abe
6import ViewResolver from 0x1d7e57aa55817448
7import DapperWalletRestrictions from 0x2d4cebdb9eca6f49
8
9access(all) fun getStorageCapability(
10    _ signer: auth(Storage, Capabilities) &Account,
11    storagePath: StoragePath,
12    capabilityType: Type
13): Capability? {
14    var capability: Capability? = nil
15    signer.capabilities.storage.forEachController(forPath: storagePath, fun (controller: &StorageCapabilityController): Bool {
16        if (!controller.capability.isInstance(capabilityType)) {
17            return true
18        }
19        capability = controller.capability
20        return false
21    })
22    return capability
23}
24
25access(all) fun getVaultCapabilities(_ signer: auth(Storage, Capabilities) &Account, vaultIdentifier: String): {String: Capability<auth(FungibleToken.Withdraw) &{FungibleToken.Provider, FungibleToken.Balance}>} {
26    let unsupportedVaultError = "unsupported vault for "
27    let missingVaultError = "missing vault for "
28    let capabilities: {String: Capability<auth(FungibleToken.Withdraw) &{FungibleToken.Provider, FungibleToken.Balance}>} = { }
29    let unsupportedError = unsupportedVaultError.concat(vaultIdentifier)
30    let vaultType = CompositeType(vaultIdentifier) ?? panic(unsupportedError)
31    let dataMap = Utils.getTypeFTVaultData([vaultType])
32    let data = dataMap[vaultType] ?? panic(unsupportedError)
33    var capability = getStorageCapability(signer, storagePath: data.storagePath, capabilityType: Type<Capability<auth(FungibleToken.Withdraw) &{FungibleToken.Vault}>>()) as! Capability<auth(FungibleToken.Withdraw) &{FungibleToken.Vault}>?
34    if (capability == nil) {
35        assert(signer.storage.type(at: Swap.SwapCollectionStoragePath) == Type<&{FungibleToken.Vault}>(), message: missingVaultError.concat(vaultType.identifier))
36        capability = signer.capabilities.storage.issue<auth(FungibleToken.Withdraw) &{FungibleToken.Vault}>(data.storagePath)
37    }
38    capabilities.insert(key: vaultType.identifier, capability!)
39    return capabilities
40}
41
42access(all) fun getNftCapabilities(_ signer: auth(Storage, Capabilities) &Account, nfts: [Swap.ProposedTradeAsset]): {String: Capability<auth(NonFungibleToken.Withdraw) &{NonFungibleToken.Collection}>} {
43    let missingError = "missing or invalid capability for "
44    let capabilities: {String: Capability<auth(NonFungibleToken.Withdraw) &{NonFungibleToken.Collection}>} = { }
45    for nft in nfts {
46        if (capabilities.containsKey(nft.type.identifier)){
47            continue
48        }
49        let capablity = getStorageCapability(signer, storagePath: nft.collectionData.storagePath, capabilityType: Type<Capability<auth(NonFungibleToken.Withdraw) &{NonFungibleToken.Collection}>>()) as! Capability<auth(NonFungibleToken.Withdraw) &{NonFungibleToken.Collection}>?
50        assert(capablity != nil && capablity!.check(), message: missingError.concat(nft.type.identifier))
51        capabilities.insert(key: nft.type.identifier, capablity!)
52    }
53    return capabilities
54}
55
56access(all) fun initializeCollections(
57    _ signer: auth(Storage, Capabilities) &Account,
58    collectionDataMap: { Type: MetadataViews.NFTCollectionData },
59    proposedNfts: [[Swap.ProposedTradeAsset]]
60): Void {
61    let initializedTypes: [Type] = []
62    for nfts in proposedNfts {
63        for nft in nfts {
64            if (initializedTypes.contains(nft.type)) {
65                continue
66            }
67            let restriction = DapperWalletRestrictions.getConfig(nft.collectionData.publicCollection)
68            assert(restriction == nil || restriction!.flags["CAN_INIT"] != false, message: "NFT type not allowed: ".concat(nft.type.identifier))
69            let collectionData = collectionDataMap[nft.type] ?? panic("collection data lookup failed for: ".concat(nft.type.identifier))
70            if (signer.storage.type(at: collectionData.storagePath) == nil) {
71                signer.storage.save(<-collectionData.createEmptyCollection(), to: collectionData.storagePath)
72            }
73            let hasPrivilegedCapability = getStorageCapability(signer, storagePath: collectionData.storagePath, capabilityType: Type<Capability<auth(NonFungibleToken.Withdraw) &{NonFungibleToken.Collection}>>()) != nil
74            if (!hasPrivilegedCapability) {
75                signer.capabilities.storage.issue<auth(NonFungibleToken.Withdraw) &{NonFungibleToken.Collection}>(collectionData.storagePath)
76            }
77            if (signer.capabilities.borrow<&{NonFungibleToken.Collection}>(collectionData.publicPath) == nil) {
78                let capability = signer.capabilities.storage.issue<&{NonFungibleToken.Collection}>(collectionData.storagePath)
79                signer.capabilities.unpublish(collectionData.publicPath)
80                signer.capabilities.publish(capability, at: collectionData.publicPath)
81            }
82            initializedTypes.append(nft.type)
83        }
84    }
85}
86
87access(all) fun getSwapManager(_ signer: auth(Storage, Capabilities) &Account): auth(Swap.CreateProposal, Swap.DeleteProposal) &Swap.SwapCollection {
88    let storedType = signer.storage.type(at: Swap.SwapCollectionStoragePath)
89    if (storedType != nil && storedType != Type<@Swap.SwapCollection>()) {
90        let oldCollection <- signer.storage.load<@AnyResource>(from: Swap.SwapCollectionStoragePath)
91        destroy oldCollection
92    }
93    if (signer.storage.type(at: Swap.SwapCollectionStoragePath) == nil) {
94        let newCollection <- Swap.createEmptySwapCollection()
95        signer.storage.save(<-newCollection, to: Swap.SwapCollectionStoragePath)
96    }
97    let hasPrivilegedCapability = getStorageCapability(signer, storagePath: Swap.SwapCollectionStoragePath, capabilityType: Type<Capability<auth(Swap.CreateProposal, Swap.DeleteProposal) &Swap.SwapCollection>>()) != nil
98    if (!hasPrivilegedCapability) {
99        signer.capabilities.storage.issue<auth(Swap.CreateProposal, Swap.DeleteProposal) &Swap.SwapCollection>(Swap.SwapCollectionStoragePath)
100    }
101    if (signer.capabilities.borrow<&Swap.SwapCollection>(Swap.SwapCollectionPublicPath) == nil) {
102        let capability = signer.capabilities.storage.issue<&Swap.SwapCollection>(Swap.SwapCollectionStoragePath)
103        signer.capabilities.unpublish(Swap.SwapCollectionPublicPath)
104        signer.capabilities.publish(capability, at: Swap.SwapCollectionPublicPath)
105    }
106    return signer.storage.borrow<auth(Swap.CreateProposal, Swap.DeleteProposal) &Swap.SwapCollection>(from: Swap.SwapCollectionStoragePath) ?? panic("invalid manager reference")
107}
108
109// v1
110transaction() {
111    let leftUserNfts: {String: [UInt64]}
112    let rightUserNfts: {String: [UInt64]}
113    let leftUserOffer: Swap.UserOffer
114    let rightUserOffer: Swap.UserOffer
115    let leftCollectionReceiverCapabilities: {String: Capability<&{NonFungibleToken.Receiver}>}
116    let leftCollectionProviderCapabilities: {String: Capability<auth(NonFungibleToken.Withdraw) &{NonFungibleToken.Provider}>}
117    var leftFeeProviderCapabilities: {String: Capability<auth(FungibleToken.Withdraw) &{FungibleToken.Provider, FungibleToken.Balance}>}
118    let signer: auth(Storage, Capabilities) &Account
119
120    prepare(signer: auth(Storage, Capabilities) &Account) {
121        self.leftUserNfts = {"A.edf9df96c92f4595.Pinnacle.NFT": [10995117615229, 97856536218702]}
122        self.rightUserNfts = {"A.edf9df96c92f4595.Pinnacle.NFT": [8796095034525]}
123        self.signer = signer
124        self.leftFeeProviderCapabilities = { }
125        let collectionDataMap = Utils.getIdentifierNFTCollectionData(self.leftUserNfts.keys.concat(self.rightUserNfts.keys))
126        let toProposedNfts = fun (ownerAddress: Address, _ nfts: { String: [UInt64] }): [Swap.ProposedTradeAsset] {
127            let proposedNfts: [Swap.ProposedTradeAsset] = []
128            nfts.forEachKey(fun (identifier: String): Bool {
129                for nftID in nfts[identifier]! {
130                    let compositeType = CompositeType(identifier) ?? panic("unable to cast type; must be a valid NFT type reference")
131                    proposedNfts.append(Swap.ProposedTradeAsset(
132                        nftID: nftID,
133                        type: compositeType,
134                        collectionData: collectionDataMap[compositeType] ?? panic("no collection data for ".concat(compositeType.identifier))
135                    ))
136                }
137                return true
138            })
139            return proposedNfts
140        }
141        let leftProposedNfts = toProposedNfts(ownerAddress: signer.address, self.leftUserNfts)
142        let rightProposedNfts = toProposedNfts(ownerAddress: 0x35879cbfc725ec4e, self.rightUserNfts)
143        initializeCollections(
144            signer,
145            collectionDataMap: collectionDataMap,
146            proposedNfts: [leftProposedNfts, rightProposedNfts]
147        )
148        Swap.assertProposedNftRestrictions(leftProposedNfts, rightProposedNfts)
149
150        if false {
151            self.leftFeeProviderCapabilities = getVaultCapabilities(signer, vaultIdentifier: ""!)
152        }
153
154        self.leftUserOffer = Swap.UserOffer(userAddress: signer.address, proposedNfts: leftProposedNfts, metadata: nil)
155        self.rightUserOffer = Swap.UserOffer(userAddress: 0x35879cbfc725ec4e, proposedNfts: rightProposedNfts, metadata: nil)
156        self.leftCollectionReceiverCapabilities = getNftCapabilities(signer, nfts: self.rightUserOffer.proposedNfts)
157        self.leftCollectionProviderCapabilities = getNftCapabilities(signer, nfts: self.leftUserOffer.proposedNfts)
158    }
159
160    execute {
161        getSwapManager(self.signer).createProposal(
162            leftUserOffer: self.leftUserOffer,
163            rightUserOffer: self.rightUserOffer,
164            leftUserCapabilities: Swap.UserCapabilities(
165                collectionReceiverCapabilities: self.leftCollectionReceiverCapabilities,
166                collectionProviderCapabilities: self.leftCollectionProviderCapabilities,
167                feeProviderCapabilities: self.leftFeeProviderCapabilities,
168                extraCapabilities: nil
169            ),
170            expirationOffsetMinutes: 1440.00000000,
171            metadata: {"environmentId": "disney"}
172        )
173    }
174}