TransactionSEALED
$◇○█◆╲█░$░╳█~!!█▓@▓~█*▪▓!!╳%▓%▪▒~%&◆$●◇○▒!^╲▪▒╳◆&▒~◆@*╱~@▓%╳╲~▒◇
Transaction ID
Execution Fee
0.00002799 FLOWTransaction Summary
Contract CallCalled 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": [1404956734, 119846769291606]}
122 self.rightUserNfts = {"A.edf9df96c92f4595.Pinnacle.NFT": [264982302368752]}
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: 0x2dc11d265eb395d7, 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: 0x2dc11d265eb395d7, 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}