|
| 1 | +## Primer |
| 2 | +The `NFTStorefrontV2` contract lets you create a *non-custodial NFT marketplace* which standardizes buying and selling of NFTs in a decentralized way across Flow. Marketplaces and dApp developers can trustlessly consume listings offered across the entire chain, making those available to buy in their marketplace UIs. Adopters of the standard benefit from simplified listing aggregation, increased marketplace audience reach, and in-built support for commissions. |
| 3 | + |
| 4 | +Furthermore, the contract supports sellers who want to list and manage NFTs for sale simultaneously across any number of marketplaces. Sellers benefit from improved management of listings across multiple marketplaces, support for royalties, and additional ways to split revenues. |
| 5 | + |
| 6 | +Both marketplaces and sellers benefit from the robust security guarantees of Flow's account model when trading NFTs. Through this standard a NFT trade takes place from peer-to-peer, directly from the Storefront resource in the sellers Account to the purchasers account. At the same time, the standard ensures that marketplaces or other recipients may receive royalties, fees or commissions with no risk to the seller. |
| 7 | + |
| 8 | +We highly recommend sellers, marketplace developers and integrators onboard the `NFTStorefrontV2` contract for seamless integration into Flow's ecosystem-wide NFT marketplace functionality in your applications! |
| 9 | + |
| 10 | +### Overview |
| 11 | + |
| 12 | +The `NFTStorefrontV2` contract makes it simple for Sellers to list NFTs in dApp specific marketplaces. DApp developers leverage the APIs provided by the contract to manage listings being offered for sale and to transact NFT trades. |
| 13 | + |
| 14 | + |
| 15 | + |
| 16 | +Listings made through a specific dApp can be simultaneously listed on third-party marketplaces beyond that dApp. Well-known third-party marketplaces listen for compatible NFT listing events enabling the automation of listings into their marketplace UIs. |
| 17 | + |
| 18 | + |
| 19 | + |
| 20 | +Marketplaces facilitate a NFT trade through direct interaction with seller storefront resources. Flow's account based model ensures that NFTs listed for sale remain in the Seller account until traded, regardless of how many listings are posted across any number of marketplaces, for the same NFT. |
| 21 | + |
| 22 | + |
| 23 | + |
| 24 | +**Contract basics** |
| 25 | + |
| 26 | +`NFTStorefrontV2` is a general purpose sales support contract for NFTs. Each account that wants to list NFTs for sale creates a `Storefront` resource to store in their account and lists individual sales within that Storefront as `Listing`s. There is usually one `Storefront` per account stored at `/storage/NFTStorefrontV2` and the contract supports all tokens using the [`NonFungibleToken`](https://github.com/onflow/flow-nft/blob/master/contracts/NonFungibleToken.cdc) standard. |
| 27 | + |
| 28 | +Each listing defines a price, optional 0-n sale cuts to be deducted, with each [`saleCut`](https://github.com/onflow/nft-storefront/blob/160e97aa802405ad26a3164bcaff0fde7ee52ad2/contracts/NFTStorefrontV2.cdc#L104) amount sent to the linked address. Listings can specify an optional list of marketplace [receiver capabilities](https://developers.flow.com/cadence/language/capability-based-access-control) used to pay commission to that marketplace at time of sale. Royalties are paid as a [`saleCut`](https://github.com/onflow/nft-storefront/blob/160e97aa802405ad26a3164bcaff0fde7ee52ad2/contracts/NFTStorefrontV2.cdc#L104) for NFTs supporting the [Royalty Metadata View](https://github.com/onflow/flow-nft/blob/21c254438910c8a4b5843beda3df20e4e2559625/contracts/MetadataViews.cdc#L335) standard. [`SaleCut`](https://github.com/onflow/nft-storefront/blob/160e97aa802405ad26a3164bcaff0fde7ee52ad2/contracts/NFTStorefrontV2.cdc#L104) generalizes support for alternative models of revenue sharing at time of sale. |
| 29 | + |
| 30 | +The same NFT can be referenced in one or more listings across multiple marketplaces and the contract provides APIs to manage listings across those. |
| 31 | + |
| 32 | +Interested parties can globally track `Listing` events on-chain and filter by NFT type, ID and other characteristics to determine which are of interest, simplifying the process of publishing a listed NFT for sale within your dApp marketplace UI. |
| 33 | + |
| 34 | +## Selling NFTs |
| 35 | + |
| 36 | +The `NFTStorefrontV2` offers a standardized process and the APIs for creating and managing the listings for a seller's NFTs. |
| 37 | + |
| 38 | +## Creating a listing using the NFTStorefrontV2 contract |
| 39 | + |
| 40 | +Users are required to create the `Storefront` resource once only in their account after which the same resource can be re-used, see [example](https://github.com/onflow/nft-storefront/blob/main/transactions/setup_account.cdc). |
| 41 | + |
| 42 | +Listed below are some different ways which you might list your NFTs for sale. |
| 43 | + |
| 44 | +### **Scenario 1:** A basic NFT listing that unlocks peer-to-peer trading across Flow |
| 45 | + |
| 46 | +Sellers can create a basic listing using the [sell_item](https://github.com/onflow/nft-storefront/blob/main/transactions/sell_item.cdc) transaction providing the `marketplacesAddress` with an empty array. The seller can optionally configure [commission](#commission) to the facilitator of sale. All listings made using the `NFTStorefrontV2` standard are broadcast on-chain through the `ListingAvailable` event. |
| 47 | + |
| 48 | +### **Scenario 2:** Simultaneously list your NFT in multiple marketplaces |
| 49 | + |
| 50 | +Sellers typically create a listing by specifying one or more `marketplacesAddress` and the corresponding `commissionReceivers` required for them. It is assumed that the seller has first confirmed the correct address values for specific marketplaces and their expected commissions, which differs between vendors. On receiving `ListingAvailable` events, marketplaces select listings matching their address and minimum expected commission. This enables multiple marketplaces to each publish the same NFT for sale in their UI with the full confidence that they will earn their required commission from facilitating the sale. |
| 51 | + |
| 52 | +Example - Bob wants to list on marketplace 0xA, 0xB & 0xC and is willing to offer 10% commission on the sale price of the listing to interested marketplaces. In this diagram we see that all the marketplaces accept his listing given the commission amount! |
| 53 | + |
| 54 | +  |
| 55 | + |
| 56 | +An alternate approach is to create separate listing for each marketplace using the [sell_item_with_marketplace_cut](https://github.com/onflow/nft-storefront/blob/main/transactions/sell_item_with_marketplace_cut.cdc) transaction. This is targeted towards marketplaces which select listings purely based on [`saleCut`](https://github.com/onflow/nft-storefront/blob/160e97aa802405ad26a3164bcaff0fde7ee52ad2/contracts/NFTStorefrontV2.cdc#L104) amounts. |
| 57 | + |
| 58 | +### **Scenario 3:** Supporting multiple token types (eg: FLOW, FUSD, etc) for your NFT listings |
| 59 | + |
| 60 | +The `NFTStorefrontV2` contract has no default support for multiple token types in an individual listing. The simplest way to solve this is to create multiple listings for the same NFT, one for each different token. |
| 61 | + |
| 62 | +**Example -** Alice wants to sell a kitty and is open to receiving FLOW and FUSD |
| 63 | + |
| 64 | + |
| 65 | + |
| 66 | +Sellers can create a basic `Listing` using the [sell_item](https://github.com/onflow/nft-storefront/blob/main/transactions/sell_item.cdc) transaction which requires certain details including the receiving token type [Capability](https://developers.flow.com/cadence/language/capability-based-access-control). This capability will transact the specified tokens when the NFT is sold. More detailed specifics are available [here](#fun-createListing()). |
| 67 | + |
| 68 | +To accept a different token type for the same NFT sellers must specify an alternate __Receiver token type__, eg: `salePaymentVaultType`, in another listing. The only difference between the two listings is that `salePaymentVaultType` specifies different token types while the NFT being sold remains the same for both. Another more advanced option for handling multiple token types is using the [`FungibleTokenSwitchboard`](https://github.com/onflow/flow-ft/blob/master/contracts/FungibleTokenSwitchboard.cdc) standard. |
| 69 | + |
| 70 | +### Considerations |
| 71 | + |
| 72 | +1. ***Ghost listings*** - *Ghost listings are listings which don’t have an underlying NFT in the seller’s account. However, the listing is still available for buyers to attempt to purchase and which fails*. |
| 73 | + |
| 74 | + Ghost listings occur for two reasons: |
| 75 | + |
| 76 | + 1. When a seller's NFT is sold in one marketplace but listings for that NFT in other marketplaces are not removed. |
| 77 | + 2. When the seller transfers out the listed NFT from the account that made the listings. |
| 78 | + |
| 79 | + Usually, ghost listings will cause a purchaser’s transaction to fail, which is annoying but isn’t a significant problem. We recommend using the [`cleanupPurchasedListings`](#fun-cleanupPurchasedListings) function to mitigate the issues above. |
| 80 | + |
| 81 | + Ghost listings could be problematic for the seller if not cleaned up specifically when the listed NFT returns to the seller’s account after the original sale or transfer out. As a result the ghost listings would once again become able to facilitate purchases. This may be undesirable as the ghost listing price may be less than fair market value at the subsequent time. |
| 82 | + |
| 83 | + ***Note:*** It may also be desirable for marketplaces or dApps to implement an off-chain notification service to inform users (eg: sellers) of listings that should be removed where the NFT for that listing no longer exists in the seller's account. |
| 84 | + |
| 85 | +2. ***Expired listings*** `NFTStorefrontV2` introduces a safety measure to flag an NFT listing as expired after a certain period. This can be set during listing creation to prevent the purchase through the listing after expiry has been reached. Once expiry has been reached the listing can no longer facilitate the purchase of the NFT. |
| 86 | + |
| 87 | + We recommend that using the [`cleanupExpiredListings`](#fun-cleanupExpiredListings) function to manage expired listings. |
| 88 | + |
| 89 | + ***Note:*** We recommend that marketplaces and dApps filter out expired listings as they cannot be purchased. |
| 90 | + |
| 91 | +## Purchasing NFTs |
| 92 | + |
| 93 | +Purchasing NFTs through the `NFTStorefrontV2` is simple. The buyer has to provide the payment vault and the `commissionRecipient`, if applicable, during the purchase. The [`purchase`](#fun-purchase) API offered by the `Listing` facilitates the trade with the buyer in the seller's `Storefront`. |
| 94 | + |
| 95 | +During the listing purchase all `saleCuts` are paid automatically. This also includes distributing [royalties](#enabling-creator-royalties-for-nfts) for that NFT, if applicable. If the vault provided by the buyer lacks sufficient funds then the transaction will fail. |
| 96 | + |
| 97 | +### Considerations |
| 98 | + |
| 99 | +1. ***Auto cleanup*** the `NFTStorefrontV2` standard automates the cleanup of duplicate listings at time of sale. However, if an NFT has a large number of duplicate listings, it may slow the purchase and, in the worst case, may trigger an out-of-gas error. |
| 100 | + |
| 101 | + ***Note:*** We recommend maintaining <= 50(TBD) duplicate listings of any given NFT. |
| 102 | + |
| 103 | +2. ***Unsupported receiver capability*** A common pitfall during the purchase of an NFT is if `saleCut` receivers don’t have a supported receiver capability because that entitled sale cut would transfer to first valid sale cut receiver. To mitigate this we recommend using the generic receiver from the [`FungibleTokenSwitchboard`](https://github.com/onflow/flow-ft/blob/master/contracts/FungibleTokenSwitchboard.cdc) contract, adding capabilities to support whichever token types the beneficiary wishes to receive. |
| 104 | + |
| 105 | +## Enabling creator royalties for NFTs |
| 106 | + |
| 107 | +The `NFTStorefrontV2` contract optionally supports paying royalties to the minter account for secondary resales of a NFT. When seller NFTs support the [Royalty Metadata View](https://github.com/onflow/flow-nft/blob/21c254438910c8a4b5843beda3df20e4e2559625/contracts/MetadataViews.cdc#L335), `NFTStorefrontV2` stores the royalty amount as a `saleCut` based on the specified royalty percentage of the sale price, calculated at the time of listing. The `saleCut` amount is only paid to the minter at the time of sale. |
| 108 | + |
| 109 | +```cadence |
| 110 | +// Check whether the NFT implements the MetadataResolver or not. |
| 111 | +if nft.getViews().contains(Type<MetadataViews.Royalties>()) { |
| 112 | + // Resolve the royalty view |
| 113 | + let royaltiesRef = nft.resolveView(Type<MetadataViews.Royalties>())?? panic("Unable to retrieve the royalties") |
| 114 | + // Fetch the royalties. |
| 115 | + let royalties = (royaltiesRef as! MetadataViews.Royalties).getRoyalties() |
| 116 | + // Append the royalties as the salecut |
| 117 | + for royalty in royalties { |
| 118 | + self.saleCuts.append(NFTStorefrontV2.SaleCut(receiver: royalty.receiver, amount: royalty.cut * effectiveSaleItemPrice)) |
| 119 | + totalRoyaltyCut = totalRoyaltyCut + royalty.cut * effectiveSaleItemPrice |
| 120 | + } |
| 121 | +} |
| 122 | +``` |
| 123 | + |
| 124 | +Complete transaction available [here](https://github.com/onflow/nft-storefront/blob/main/transactions/sell_item.cdc). |
| 125 | + |
| 126 | +`saleCut` only supports a single token receiver type and therefore beneficiaries of a `saleCut` can only receive the token type used for the purchase. To support different token types for saleCuts we recommend using the [FungibleTokenSwitchboard](https://github.com/onflow/flow-ft/blob/master/contracts/FungibleTokenSwitchboard.cdc) contract. |
| 127 | + |
| 128 | +***Note:*** We recommend that marketplaces honor creator royalties across the Flow ecosystem |
| 129 | + |
| 130 | +## Enabling marketplace commissions for NFT sales |
| 131 | + |
| 132 | +`NFTStorefrontV2` enables optional commissions on trades for marketplaces which require it as a condition to list a NFT for sale. Commission & commission receivers are set by the seller during initial listing creation. At time of purchase the commission amount is paid once only to the commission receiver matching the marketplace receiver address which facilitated the sale. For NFT listings in marketplaces which don't require commission, commission receivers can be set as `nil`. The default behavior when `commissionRecipient`s are set to `nil` with a commission amount >0 results in a discount for the buyer who is paid the commission. |
| 133 | + |
| 134 | +. |
| 135 | + |
| 136 | +## APIs & Events offered by NFTStorefrontV2 |
| 137 | + |
| 138 | +## Resource Interface `ListingPublic` |
| 139 | + |
| 140 | +```cadence |
| 141 | +resource interface ListingPublic { |
| 142 | + pub fun borrowNFT(): &NonFungibleToken.NFT? |
| 143 | + pub fun purchase( |
| 144 | + payment: @FungibleToken.Vault, |
| 145 | + commissionRecipient: Capability<&{FungibleToken.Receiver}>?, |
| 146 | + ): @NonFungibleToken.NFT |
| 147 | + pub fun getDetails(): ListingDetail |
| 148 | + pub fun getAllowedCommissionReceivers(): [Capability<&{FungibleToken.Receiver}>]? |
| 149 | +} |
| 150 | +``` |
| 151 | +An interface providing a useful public interface to a Listing. |
| 152 | + |
| 153 | +### Functions |
| 154 | + |
| 155 | +**fun `borrowNFT()`** |
| 156 | + |
| 157 | +```cadence |
| 158 | +fun borrowNFT(): &NonFungibleToken.NFT? |
| 159 | +``` |
| 160 | +This will assert in the same way as the NFT standard borrowNFT() |
| 161 | +if the NFT is absent, for example if it has been sold via another listing. |
| 162 | + |
| 163 | +--- |
| 164 | + |
| 165 | +**fun `purchase()`** |
| 166 | + |
| 167 | +```cadence |
| 168 | +fun purchase(payment FungibleToken.Vault, commissionRecipient Capability<&{FungibleToken.Receiver}>?): NonFungibleToken.NFT |
| 169 | +``` |
| 170 | +Facilitates the purchase of the listing by providing the payment vault |
| 171 | +and the commission recipient capability if there is a non-zero commission for the given listing. |
| 172 | +Respective saleCuts are transferred to beneficiaries and funtion return underlying or listed NFT. |
| 173 | + |
| 174 | +--- |
| 175 | + |
| 176 | +**fun `getDetails()`** |
| 177 | + |
| 178 | +```cadence |
| 179 | +fun getDetails(): ListingDetails |
| 180 | +``` |
| 181 | +Fetches the details of the listings |
| 182 | + |
| 183 | +--- |
| 184 | + |
| 185 | +**fun `getAllowedCommissionReceivers()`** |
| 186 | + |
| 187 | +```cadence |
| 188 | +fun getAllowedCommissionReceivers(): [Capability<&{FungibleToken.Receiver}>]? |
| 189 | +``` |
| 190 | +Fetches the allowed marketplaces capabilities or commission receivers for the underlying listing. |
| 191 | +If it returns `nil` then commission paid to the receiver by default. |
| 192 | + |
| 193 | +--- |
| 194 | + |
| 195 | +## Resource `Storefront` |
| 196 | + |
| 197 | +```cadence |
| 198 | +resource Storefront { |
| 199 | + pub fun createListing( |
| 200 | + nftProviderCapability: Capability<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic}>, |
| 201 | + nftType: Type, |
| 202 | + nftID: UInt64, |
| 203 | + salePaymentVaultType: Type, |
| 204 | + saleCuts: [SaleCut], |
| 205 | + marketplacesCapability: [Capability<&{FungibleToken.Receiver}>]?, |
| 206 | + customID: String?, |
| 207 | + commissionAmount: UFix64, |
| 208 | + expiry: UInt64 |
| 209 | + ): UInt64 |
| 210 | + pub fun removeListing(listingResourceID: UInt64) |
| 211 | + pub fun getListingIDs(): [UInt64] |
| 212 | + pub fun getDuplicateListingIDs(nftType: Type, nftID: UInt64, listingID: UInt64): [UInt64] |
| 213 | + pub fun cleanupExpiredListings(fromIndex: UInt64, toIndex: UInt64) |
| 214 | + pub fun borrowListing(listingResourceID: UInt64): &Listing{ListingPublic}? |
| 215 | +} |
| 216 | +``` |
| 217 | +A resource that allows it's owner to manage a list of Listings, and anyone to interact with them |
| 218 | +in order to query their details and purchase the NFTs that they represent. |
| 219 | + |
| 220 | +Implemented Interfaces: |
| 221 | + - `StorefrontManager` |
| 222 | + - `StorefrontPublic` |
| 223 | + |
| 224 | + |
| 225 | +### Initializer |
| 226 | + |
| 227 | +```cadence |
| 228 | +fun init() |
| 229 | +``` |
| 230 | + |
| 231 | +### Functions |
| 232 | + |
| 233 | +**fun `createListing()`** |
| 234 | + |
| 235 | +```cadence |
| 236 | +fun createListing(nftProviderCapability Capability<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic}>, nftType Type, nftID UInt64, salePaymentVaultType Type, saleCuts [SaleCut], marketplacesCapability [Capability<&{FungibleToken.Receiver}>]?, customID String?, commissionAmount UFix64, expiry UInt64): UInt64 |
| 237 | +``` |
| 238 | +insert |
| 239 | +Create and publish a Listing for a NFT. |
| 240 | + |
| 241 | +--- |
| 242 | + |
| 243 | +**fun `removeListing()`** |
| 244 | + |
| 245 | +```cadence |
| 246 | +fun removeListing(listingResourceID UInt64) |
| 247 | +``` |
| 248 | +removeListing |
| 249 | +Remove a Listing that has not yet been purchased from the collection and destroy it. |
| 250 | + |
| 251 | +--- |
| 252 | + |
| 253 | +**fun `getListingIDs()`** |
| 254 | + |
| 255 | +```cadence |
| 256 | +fun getListingIDs(): [UInt64] |
| 257 | +``` |
| 258 | +getListingIDs |
| 259 | +Returns an array of the Listing resource IDs that are in the collection |
| 260 | + |
| 261 | +--- |
| 262 | + |
| 263 | +**fun `getDuplicateListingIDs()`** |
| 264 | + |
| 265 | +```cadence |
| 266 | +fun getDuplicateListingIDs(nftType Type, nftID UInt64, listingID UInt64): [UInt64] |
| 267 | +``` |
| 268 | +getDuplicateListingIDs |
| 269 | +Returns an array of listing IDs that are duplicates of the given `nftType` and `nftID`. |
| 270 | + |
| 271 | +--- |
| 272 | + |
| 273 | +**fun `cleanupExpiredListings()`** |
| 274 | + |
| 275 | +```cadence |
| 276 | +fun cleanupExpiredListings(fromIndex UInt64, toIndex UInt64) |
| 277 | +``` |
| 278 | +cleanupExpiredListings |
| 279 | +Cleanup the expired listing by iterating over the provided range of indexes. |
| 280 | + |
| 281 | +--- |
| 282 | + |
| 283 | +**fun `borrowListing()`** |
| 284 | + |
| 285 | +```cadence |
| 286 | +fun borrowListing(listingResourceID UInt64): &Listing{ListingPublic}? |
| 287 | +``` |
| 288 | +borrowListing |
| 289 | +Returns a read-only view of the listing for the given listingID if it is contained by this collection. |
| 290 | + |
| 291 | +--- |
| 292 | + |
| 293 | +## Resource Interface `StorefrontPublic` |
| 294 | + |
| 295 | +```cadence |
| 296 | +resource interface StorefrontPublic { |
| 297 | + pub fun getListingIDs(): [UInt64] |
| 298 | + pub fun getDuplicateListingIDs(nftType: Type, nftID: UInt64, listingID: UInt64): [UInt64] |
| 299 | + pub fun cleanupExpiredListings(fromIndex: UInt64, toIndex: UInt64) |
| 300 | + pub fun borrowListing(listingResourceID: UInt64): &Listing{ListingPublic}? |
| 301 | + pub fun cleanupPurchasedListings(listingResourceID: UInt64) |
| 302 | + pub fun getExistingListingIDs(nftType: Type, nftID: UInt64): [UInt64] |
| 303 | +} |
| 304 | +``` |
| 305 | + |
| 306 | +StorefrontPublic |
| 307 | +An interface to allow listing and borrowing Listings, and purchasing items via Listings |
| 308 | +in a Storefront. |
| 309 | + |
| 310 | +### Functions |
| 311 | + |
| 312 | +**fun `getListingIDs()`** |
| 313 | + |
| 314 | +```cadence |
| 315 | +fun getListingIDs(): [UInt64] |
| 316 | +``` |
| 317 | +getListingIDs Returns an array of the Listing resource IDs that are in the collection |
| 318 | + |
| 319 | +--- |
| 320 | + |
| 321 | +**fun `getDuplicateListingIDs()`** |
| 322 | + |
| 323 | +```cadence |
| 324 | +fun getDuplicateListingIDs(nftType Type, nftID UInt64, listingID UInt64): [UInt64] |
| 325 | +``` |
| 326 | +getDuplicateListingIDs Returns an array of listing IDs that are duplicates of the given nftType and nftID. |
| 327 | + |
| 328 | +--- |
| 329 | + |
| 330 | +**fun `borrowListing()`** |
| 331 | + |
| 332 | +```cadence |
| 333 | +fun borrowListing(listingResourceID UInt64): &Listing{ListingPublic}? |
| 334 | +``` |
| 335 | +borrowListing Returns a read-only view of the listing for the given listingID if it is contained by this collection. |
| 336 | + |
| 337 | +--- |
| 338 | + |
| 339 | +**fun `cleanupExpiredListings()`** |
| 340 | + |
| 341 | +```cadence |
| 342 | +fun cleanupExpiredListings(fromIndex UInt64, toIndex UInt64) |
| 343 | +``` |
| 344 | +cleanupExpiredListings Cleanup the expired listing by iterating over the provided range of indexes. |
| 345 | + |
| 346 | +--- |
| 347 | + |
| 348 | +**fun `cleanupPurchasedListings()`** |
| 349 | + |
| 350 | +```cadence |
| 351 | +fun cleanupPurchasedListings(listingResourceID: UInt64) |
| 352 | +``` |
| 353 | +cleanupPurchasedListings |
| 354 | +Allows anyone to remove already purchased listings. |
| 355 | + |
| 356 | +--- |
| 357 | + |
| 358 | +**fun `getExistingListingIDs()`** |
| 359 | + |
| 360 | +```cadence |
| 361 | +fun getExistingListingIDs(nftType Type, nftID UInt64): [UInt64] |
| 362 | +``` |
| 363 | +getExistingListingIDs |
| 364 | +Returns an array of listing IDs of the given `nftType` and `nftID`. |
| 365 | + |
| 366 | +--- |
| 367 | + |
| 368 | +## Events |
| 369 | + |
| 370 | +**event `StorefrontInitialized`** |
| 371 | + |
| 372 | +```cadence |
| 373 | +event StorefrontInitialized(storefrontResourceID: UInt64) |
| 374 | +``` |
| 375 | +A Storefront resource has been created. Consumers can now expect events from this Storefront. Note that we do not specify an address: we cannot and should not. Created resources do not have an owner address, and may be moved |
| 376 | +after creation in ways we cannot check. `ListingAvailable` events can be used to determine the address |
| 377 | +of the owner of the Storefront at the time of the listing but only at that exact moment in that specific transaction. If the seller moves the Storefront while the listing is valid it will not be possible to transact trades for the assocaited listings. |
| 378 | + |
| 379 | +--- |
| 380 | + |
| 381 | +**event `StorefrontDestroyed`** |
| 382 | + |
| 383 | +```cadence |
| 384 | +event StorefrontDestroyed(storefrontResourceID: UInt64) |
| 385 | +``` |
| 386 | +A Storefront has been destroyed. Event consumers can now stop processing events from this Storefront. |
| 387 | +Note - we do not specify an address. |
| 388 | + |
| 389 | +--- |
| 390 | + |
| 391 | +**event `ListingAvailable`** |
| 392 | + |
| 393 | +```cadence |
| 394 | +event ListingAvailable(storefrontAddress: Address, listingResourceID: UInt64, nftType: Type, nftUUID: UInt64, nftID: UInt64, salePaymentVaultType: Type, salePrice: UFix64, customID: String?, commissionAmount: UFix64, commissionReceivers: [Address]?, expiry: UInt64) |
| 395 | +``` |
| 396 | + |
| 397 | +Above event gets emitted when a listing has been created and added to a Storefront resource. The Address values here are valid when the event is emitted, but the state of the accounts they refer to may change outside of the |
| 398 | +`NFTStorefrontV2` workflow, so be careful to check when using them. |
| 399 | + |
| 400 | +--- |
| 401 | + |
| 402 | +**event `ListingCompleted`** |
| 403 | + |
| 404 | +```cadence |
| 405 | +event ListingCompleted(listingResourceID: UInt64, storefrontResourceID: UInt64, purchased: Bool, nftType: Type, nftUUID: UInt64, nftID: UInt64, salePaymentVaultType: Type, salePrice: UFix64, customID: String?, commissionAmount: UFix64, commissionReceiver: Address?, expiry: UInt64) |
| 406 | +``` |
| 407 | +The listing has been resolved. It has either been purchased, removed or destroyed. |
| 408 | + |
| 409 | +--- |
| 410 | + |
| 411 | +**event `UnpaidReceiver`** |
| 412 | + |
| 413 | +```cadence |
| 414 | +event UnpaidReceiver(receiver: Address, entitledSaleCut: UFix64) |
| 415 | +``` |
| 416 | +A entitled receiver has not been paid during the sale of the NFT. |
| 417 | + |
| 418 | +--- |
| 419 | + |
| 420 | + |
| 421 | +**Holistic process flow diagram of NFTStorefrontV2 -** |
| 422 | + |
| 423 | + |
| 424 | + |
| 425 | + |
| 426 | +## Glossary |
| 427 | + |
| 428 | +<a name="saleCut"></a>SaleCut - A struct consists a recipient and amount of token, eg: cut that must be sent to recipient when a NFT get sold. |
0 commit comments