TransactionSEALED
░^░╳░□□&╳▓*□╱&╱▫╲░□▪@?^▪?╱~&?╳@╲░▓#%░╳*■&%$╱~$█╳╲~?□^◆▪□◇~&□▓*□%
Transaction ID
Payer
Proposerseq:0 key:0
Authorizers
2Transaction Summary
Contract CallCalled OffersV2, DapperOffersV2, AllDay +4 more
Script Arguments
0amountUFix64
3.00000000
1royalties{Address
{
"0xe4cf4bdc1751c65d": "0.15000000"
}2offerParamsString{String
{
"editionId": "4897",
"_type": "EDITION"
}Cadence Script
1import OffersV2 from 0xb8ea91944fd51c43
2import DapperOffersV2 from 0xb8ea91944fd51c43
3import AllDay from 0xe4cf4bdc1751c65d
4import NonFungibleToken from 0x1d7e57aa55817448
5import FungibleToken from 0xf233dcee88fe0abe
6import DapperUtilityCoin from 0xead892083b3e2c6c
7import Resolver from 0xb8ea91944fd51c43
8
9/// This transaction creates an offer to exchange a AllDay NFT for DapperUtilityCoin.
10///
11/// @param amount: The amount of DapperUtilityCoin to offer for the NFT.
12/// @param royalties: A dictionary of royalties to pay out for the NFT sale.
13/// @param offerParamsString: A dictionary of offer parameters. If only a editionId is provided, an edition offer
14/// is created. If a serialNumber is also provided, a serial offer is created, meaning only the NFT with the
15/// provided serial number from the provided edition can be accepted with this offer.
16///
17transaction(amount: UFix64, royalties: {Address:UFix64}, offerParamsString: {String:String}) {
18 var nftReceiver: Capability<&{NonFungibleToken.CollectionPublic}>?
19 let dapperOfferRef: auth(DapperOffersV2.Manager) &DapperOffersV2.DapperOffer
20 var ducWithdrawCap: Capability<auth(FungibleToken.Withdraw) &{FungibleToken.Vault}>
21 let resolverCap: Capability<&{Resolver.ResolverPublic}>
22 var proxyManagerCap: Capability<auth(DapperOffersV2.ProxyManager) &DapperOffersV2.DapperOffer>
23
24 prepare(signer: auth(Storage, Capabilities) &Account, dapper: auth(Storage, Capabilities) &Account) {
25 // Create and publish a new AllDay collection if the signer account doesn't already have one
26 if signer.storage.borrow<&AllDay.Collection>(from: AllDay.CollectionStoragePath) == nil {
27 signer.storage.save(<- AllDay.createEmptyCollection(nftType: Type<@AllDay.NFT>()), to: AllDay.CollectionStoragePath)
28 signer.capabilities.unpublish(AllDay.CollectionPublicPath)
29 signer.capabilities.publish(
30 signer.capabilities.storage.issue<&AllDay.Collection>(AllDay.CollectionStoragePath),
31 at: AllDay.CollectionPublicPath
32 )
33 }
34
35 // Get the AllDay collection receiver capability, republishing if missing
36 self.nftReceiver = signer.capabilities.get<&{NonFungibleToken.CollectionPublic}>(AllDay.CollectionPublicPath)
37 if self.nftReceiver == nil || !self.nftReceiver!.check() {
38 signer.capabilities.unpublish(AllDay.CollectionPublicPath)
39 signer.capabilities.publish(
40 signer.capabilities.storage.issue<&{NonFungibleToken.CollectionPublic}>(AllDay.CollectionStoragePath),
41 at: AllDay.CollectionPublicPath
42 )
43 self.nftReceiver = signer.capabilities.get<&{NonFungibleToken.CollectionPublic}>(AllDay.CollectionPublicPath)
44 }
45
46 // Create and publish a new DapperOffers resource if the signer account doesn't already have one
47 if signer.storage.borrow<&DapperOffersV2.DapperOffer>(from: DapperOffersV2.DapperOffersStoragePath) == nil {
48 signer.storage.save(<- DapperOffersV2.createDapperOffer(), to: DapperOffersV2.DapperOffersStoragePath)
49 signer.capabilities.unpublish(DapperOffersV2.DapperOffersPublicPath)
50 signer.capabilities.publish(
51 signer.capabilities.storage.issue<&DapperOffersV2.DapperOffer>(DapperOffersV2.DapperOffersStoragePath),
52 at: DapperOffersV2.DapperOffersPublicPath
53 )
54 }
55
56 // Get authorized reference to the DapperOffers resource
57 self.dapperOfferRef = signer.storage.borrow<auth(DapperOffersV2.Manager) &DapperOffersV2.DapperOffer>(from: DapperOffersV2.DapperOffersStoragePath)
58 ?? panic("Could not borrow DapperOffersV2.DapperOffer")
59
60 // Create authorized capability to the DapperOffers resource and add to the dapper account to allow cancelling on behalf of the signer (e.g., balance got too low)
61 let dapperOfferProxyManagerCapPath = /storage/DapperOfferProxyManagerCapability
62 var dapperOfferProxyManagerCap = signer.storage.copy<Capability<auth(DapperOffersV2.ProxyManager) &DapperOffersV2.DapperOffer>>(from: dapperOfferProxyManagerCapPath)
63 if dapperOfferProxyManagerCap == nil || !dapperOfferProxyManagerCap!.check() {
64 self.proxyManagerCap = signer.capabilities.storage.issue<auth(DapperOffersV2.ProxyManager) &DapperOffersV2.DapperOffer>(DapperOffersV2.DapperOffersStoragePath)
65 // save capability to storage
66 signer.capabilities.storage.getController(byCapabilityID: self.proxyManagerCap.id)!.setTag("DapperOfferProxyManagerCap")
67 signer.storage.save(
68 self.proxyManagerCap,
69 to: dapperOfferProxyManagerCapPath
70 )
71 } else {
72 self.proxyManagerCap = dapperOfferProxyManagerCap!
73 }
74 dapper.capabilities.borrow<&DapperOffersV2.DapperOffer>(/public/DapperOffersV2)!.addProxyCapability(
75 account: signer.address,
76 cap: self.proxyManagerCap,
77 )
78
79
80 // Create authorized capability to withdraw from the dapper account's DUC vault
81 let ducWithdrawCapPath = /storage/DUCWithdrawCapabilityForOffers
82 var ducWithdrawCap = dapper.storage.copy<Capability<auth(FungibleToken.Withdraw) &{FungibleToken.Vault}>>(from: ducWithdrawCapPath)
83 if ducWithdrawCap == nil || !ducWithdrawCap!.check() {
84 self.ducWithdrawCap = dapper.capabilities.storage.issue<auth(FungibleToken.Withdraw) &{FungibleToken.Vault}>(/storage/dapperUtilityCoinVault)
85 // save capability to storage
86 dapper.capabilities.storage.getController(byCapabilityID: self.ducWithdrawCap.id)!.setTag("OffersDUCWithdrawCap")
87 dapper.storage.save(
88 self.ducWithdrawCap,
89 to: ducWithdrawCapPath
90 )
91 } else{
92 self.ducWithdrawCap = ducWithdrawCap!
93 }
94
95 // Create and publish a new Resolver resource if the signer account doesn't already have one
96 if signer.storage.borrow<&Resolver.OfferResolver>(from: /storage/OfferResolver) == nil {
97 signer.storage.save(<- Resolver.createResolver(), to: /storage/OfferResolver)
98 signer.capabilities.unpublish(/public/OfferResolver)
99 signer.capabilities.publish(
100 signer.capabilities.storage.issue<&Resolver.OfferResolver>(/storage/OfferResolver),
101 at: /public/OfferResolver
102 )
103 }
104
105 // Get the Resolver capability
106 self.resolverCap = signer.capabilities.get<&{Resolver.ResolverPublic}>(/public/OfferResolver)
107 }
108
109 // Validate transaction parameters
110 pre {
111 (royalties[0xe4cf4bdc1751c65d] == 0.05000000 * amount): "Missing or mis-typed royalty information"
112 (royalties.keys.length == 1): "please provide only one royalty address"
113 (offerParamsString.containsKey("editionId")): "editionId missing from offerParamsString"
114 (offerParamsString.containsKey("_type")): "Invalid offerParamsString"
115 }
116
117 execute {
118 // Create royalties list for the offer
119 var royaltysList: [OffersV2.Royalty] = []
120 for key in royalties.keys {
121 royaltysList.append(OffersV2.Royalty(
122 receiver: getAccount(key).capabilities.get<&{FungibleToken.Receiver}>(/public/dapperUtilityCoinReceiver)!,
123 amount: royalties[key]!
124 ))
125 }
126
127 // Add offer parameters
128 offerParamsString.insert(key: "typeId", "Type<@AllDay.NFT>()")
129 offerParamsString.insert(key: "resolver", Resolver.ResolverType.EditionIdAndSerialNumberTraits.rawValue.toString())
130 var offerType = "EDITION"
131 if offerParamsString.containsKey("serialNumber"){
132 offerType = "NFT"
133 }
134 offerParamsString.insert(key: "_type", offerType)
135
136 // Create the offer
137 self.dapperOfferRef.createOffer(
138 vaultRefCapability: self.ducWithdrawCap,
139 nftReceiverCapability: self.nftReceiver!,
140 nftType: Type<@AllDay.NFT>(),
141 amount: amount,
142 royalties: royaltysList,
143 offerParamsString: offerParamsString,
144 offerParamsUFix64: {},
145 offerParamsUInt64: {},
146 resolverCapability: self.resolverCap
147 )
148 }
149}