NFT Storefront Smart Contract

[Previous << NFT Metadata](https://qiita.com/flowcadence/items/191e2e765391e636a89c)
[Next >> Staking Collection](https://qiita.com/flowcadence/items/89d155bb9a803da06b45)

https://qiita.com/flowcadence/items/3073d69c6e9895e68b5a#flow-developers

`NFTStorefront`のスマートコントラクトは、NFTを販売用にリストアップし、そのリストから購入するための標準的な方法を実装しています。`NFTStorefrontV2`はより強力で機能が豊富なバージョンであるため、開発者およびユーザーは`NFTStorefront`または独自の実装ではなく、こちらを使用することをお勧めします。

Source: [NFTStorefrontV2.cdc](https://github.com/onflow/nft-storefront/blob/main/contracts/NFTStorefrontV2.cdc)

| Network | Contract Address |
|:-:|:-:|
| Testnet | `0x2d55b98eb200daef` |
| Mainnet | `0x4eb8a10cb9f87357` |

Source: [NFTStorefront.cdc](https://github.com/onflow/nft-storefront/blob/main/contracts/NFTStorefront.cdc)

| Network | Contract Address |
|:-:|:-:|
| Testnet | `0x94b06cfca1d8a476` |
| Mainnet | `0x4eb8a10cb9f87357` |

<h1>Primer</h1>

`NFTStorefrontV2`スマートコントラクトにより、FLOWブロックチェーン上で*非管理型(non-custodial)リソース（NFT）マーケットプレイス* を作成することができます。

`NFTStorefrontV2`により、販売者はdApp専用マーケットプレイスにNFTを簡単にリストアップすることができます。dApp開発者は、このコントラクトが提供するAPIを活用して、販売中のリストを管理し、NFT取引を行うことができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3912821/b5bf3d82-4bcc-aec5-6430-66923c80c772.png)

開発者は`NFTStorefrontV2`を使用して、マーケットプレイスを作成し、ピアツーピアでの購入を可能にすべきです。以下の図は、dAppsが異なるマーケットプレイスにおけるNFTの出品を円滑にする方法と、マーケットプレイスが出品をフィルタリングする方法を示しています。

特定のdAppストアフロント(storefront)を通じて作成された出品は、そのdAppの枠を超えてサードパーティのマーケットプレイスにも同時に出品することができます。よく知られたサードパーティのマーケットプレイスは、互換性のあるNFT出品イベントを監視しており、それらのマーケットプレイスのダッシュボードへの出品の自動化を可能にしています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3912821/4b2254dc-49fc-d1f3-3c47-6c76ea7ecb95.png)

`NFTStorefrontV2`を使用することで、マーケットプレイスは活気のあるFLOW NFTエコシステムに対して、即座かつ簡単にアクセスでき、NFT保有者がNFTを出品できるようにし、クリエイターのロイヤリティを可能にします。

マーケットプレイスは、売り手のストアフロントと直接やりとりすることで、NFT取引を処理します。Flowのアカウントベースのモデルでは、同じNFTが複数のマーケットプレイスにいくつ掲載されていても、NFTが取引されるまで、売り手のアカウントに常に存在することが保証されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3912821/3b2c2086-448e-69d3-11c3-2a212523edc3.png)

<h1>Functional Overview</h1>

Flow [`NonFungibleToken`](https://github.com/onflow/flow-nft/blob/master/contracts/NonFungibleToken.cdc) 標準(standard)を実装した、 NFT の汎用的販売サポートコントラクト。NFT を販売したい各アカウントは、`Storefront` リソースを作成し、アカウント内に保存します。その Storefront 内にListings として、個々の販売を リスティングします。通常、アカウントごとに 1 つの `/storage/NFTStorefrontV2` に保持されたStorefront があります。

各出品では、販売価格から差し引かれる1つまたは複数の販売カット(補足: =サービス手数料)を、1つまたは複数のアドレスに送るように定義できます。出品手数料、ロイヤリティ、またはその他の対価は、販売カットを使用して支払うことができます。また、出品には、購入を促進した人物に対して支払われる、販売カットの1つの手数料を含めることができます。

出品には、出品を履行したことに対する手数料を受け取るための、任意のマーケットプレイス [receiver capabilities](https://qiita.com/flowcadence/items/85e1aaf7e41d1134fa6c) のリストを持つことができます。NFTは1つ以上のListingsに出品することができ、各出品の有効性は簡単に確認できます。

関係者は、オンチェーンで出品イベントをグローバルに追跡し、NFTタイプ、ID、その他の特性でフィルタリングして、彼ら自身のマーケットプレイスUI内で、購入可能にするものをどれにするか決定することができます。
<h1>Selling NFTs</h1>

`NFTStorefrontV2`は、NFTの出品を作成するための一般的なプロセスを提供します。出品を個別に管理するためのすべての必須APIを提供します。

多くのマーケットプレイスでは、異なる個々の出品を管理するために単一のストアフロントリソースを作成します。信頼性が高く、プラットフォームに依存しないように、ユーザー所有のストアフロントリソースの下に出品を作成することをお勧めします。ユーザーは、ストアフロント スマートコントラクトを使用して出品を作成するために、アカウントの下に`Storefront`リソースを保有する必要があります。


<h1>Creating a successful listing using the NFTStorefrontV2 contract.</h1>

上記で推奨したように、ファーストステップは、[setup_account](https://github.com/onflow/nft-storefront/blob/main/transactions/setup_account.cdc) トランザクションを使用して、[Storefrontリソース](#resource-storefront)を作成してユーザーアカウント内に保存することです。

次のステップは、新しく作成したStorefrontリソースの下にlisting(出品)を作成することです。ユーザーがすでにStorefrontリソースを保持している場合は、既存のリソースを使用します。売り手は、NFTを出品するために複数の要件を提示できます。そして、私たちはそれらのほとんどをカバーするために、下に書かれているように最善を尽くしています。
<h3>Scenario 1: Selling NFTs corresponds to more than one cryptocurrency, i.e. FLOW, USDC etc.</h3>

`NFTStorefrontV2` スマートコントラクトでは、1回の出品で複数の異なる通貨によるNFTの販売をサポートしていません。しかし、これは、異なる通貨ごとに同じNFTの複数の出品を作成することで実現できます。

**Example** - アリスは(デジタルの)子猫を売りたいと思っており、FLOWとUSDCを受け取ることに前向きである。(補足: 子猫が登場するのはFlow作者がCryptoKittiesの作者だからです)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3912821/839fe104-387c-95f7-21cf-d6a3074d87ad.png)

NFTを販売することを「出品」と呼び、売り手はNFTを出品するために[sell_item](https://github.com/onflow/nft-storefront/blob/main/transactions/sell_item.cdc)トランザクションを使用して、必要な詳細情報を提供することにより、出品を作成することができます。例えば、受け取り通貨の種類、NFTが差し引かれる[Capability](https://qiita.com/flowcadence/items/85e1aaf7e41d1134fa6c)などです。興味のある方は、[`createListing`](#fun-createlisting)にて詳細をご覧ください。

異なる通貨を受け取るためには、売り手は異なる**Receiver currency type**、すなわち`salePaymentVaultType`を提供する必要があります。上記の図に示されているように、ほぼ同じ入力で2つの出品フォームがあります。唯一の違いは、`salePaymentVaultType`パラメータであり、異なる販売通貨タイプで重複するNFT出品を作成する場合は、異なる値にする必要があります。
<h3>Scenario 2: Peer-to-Peer (p2p) listing of NFT: A listing anyone can fulfil.</h3>

Dappsは**NFTStorefrontV2**を活用して、マーケットプレイスとは独立した形で販売者の出品を促進することができます。Dappsやマーケットプレイスは、それらの出品をそれぞれのプラットフォームに掲載することができます。または、販売者がピアツーピアで決済することも可能です。

売り手は、p2pの出品を作成するために[sell_item](https://github.com/onflow/nft-storefront/blob/main/transactions/sell_item.cdc)トランザクションを使用して、`marketplacesAddress`に空の配列を指定します。売り手は、販売の仲介者に[commission(手数料)](#enabling-marketplace-commissions-for-nft-sales)を支払うかどうかの選択肢があり、仲介者と購入者が同一の場合は、手数料を割引として適用することもできます。
<h3>Scenario 3: The seller wants to list its NFT in different marketplaces.</h3>

`NFTStorefrontV2` では、2つの異なる方法を提供しています。
* 売り手は、出品を作成し、sell_item トランザクションを使用して、これから出品を希望する`marketplacesAddress`を提供することができます。
マーケットプレイスは、`ListingAvailable` イベントを監視し、`commissionReceivers` リストに自身のアドレスが含まれているかどうかを確認することができます。出品が成功裏に完了した際に報酬が支払われることになります。
Example - ボブはマーケットプレイス0xA、0xB、0xCに出品したいと考えており、出品の販売価格の10%をマーケットプレイスに手数料として提供する意思があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3912821/ef3b8527-a1dd-de8b-88aa-c8d815fd4e98.png)

* もう一つの方法は、[sell_item_with_marketplace_cut](https://github.com/onflow/nft-storefront/blob/main/transactions/sell_item_with_marketplace_cut.cdc) トランザクションを使用して、ユーザーが自分の出品を希望する各マーケットプレイスに対して個別の出品を作成することです。この場合、マーケットプレイスは、出品の作成時に`saleCuts`配列にmarketplace saleCutを追加することで、[`saleCut`](https://github.com/onflow/nft-storefront/blob/160e97aa802405ad26a3164bcaff0fde7ee52ad2/contracts/NFTStorefrontV2.cdc#L104)の1部を獲得することでインセンティブを得ることができます。
<h3>Considerations</h3>

1. **ゴースト出品** - *ゴースト出品とは、売り手のアカウントにNFTが存在しない出品のことです。ただし、その出品は購入者が購入を試みることは可能です*。StorefrontV2はゴースト出品を完全に排除できるわけではありません。通常、ゴースト出品は購入者のトランザクションを失敗させますが、これは厄介ではあるものの、重大な問題ではありません。ゴースト出品が売り手にとって問題となるのは、出品されたNFTが最初の販売後に売り手のアカウントに戻ってきた場合です。ゴースト出品は、戻ってきた時点で無効ではなくなり、売り手がその価格で販売したくない場合でも、誰でも購入することができます。
**Note** - *マーケットプレイスやピアツーピアのdAppsは、ユーザー（つまり売り手）がNFTを同じアカウントで保有していない場合は出品を削除するよう伝えるオフチェーン通知サービスを作成することをお勧めします。*
1. **期限切れの出品** -` NFTStorefrontV2` では、出品が作成時に設定できる一定期間後に期限切れとなり、誰も購入できなくなるという安全対策が導入されています。これは完璧な安全対策ではありませんが、ゴースト出品や期限切れ出品に対する売り手の安全対策にはなります。

**Note** - *マーケットプレイスやピアツーピアの分散型アプリケーションでは、期限切れのリストをダッシュボードに表示しないことを推奨します。*
<h1>Purchasing NFTs</h1>

`NFTStorefrontV2` を通じて NFT を購入するのは簡単です。購入者は購入時に、支払いVaultと、必要に応じて`commissionRecipient`を提供する必要があります。p2p dApps では、出品の購入を仲介する第三者は必要ありません。`Listing`リソースによって提供される [`purchase`](#fun-purchase) API を使用して、NFT の購入が実行されます。

出品物の購入時には、すべてのsaleCutsが(関係各所に)自動的に支払われます。これには、該当する場合、そのNFTのロイヤリティの分配も含まれます。購入者が提供したvaultに十分な資金がない場合、トランザクションは失敗します。
<h3>Considerations</h3>

1. **自動クリーンアップ** - `NFTStorefrontV2` は、購入中に重複した出品を自動的にクリーンアップするユニークな機能を提供します。 但し、それは1つのNFTに数千の(異なるマーケットプレイスに)重複した出品がある場合、欠点があります。 ガス不足エラーが発生する可能性が高いため、出品のいずれかを購入する際のボトルネックとなります。
**Note** - *任意のNFTの重複出品は50（未定）を超えないことをお勧めします。*
1. **サポートされていないreceiver capability** - NFTの購入時にありがちな落とし穴として、一部のsaleCut receiverがサポートされていないreceiver capabilityを持っていることが挙げられます。これは、その権利あるsaleCutが最初に有効となったsale cut receiverに送金されるためです。しかし、[`FungibleTokenSwitchboard`](https://github.com/onflow/flow-ft/blob/master/contracts/FungibleTokenSwitchboard.cdc)スマートコントラクトを使用して汎用receiverを提供し、受益者が受け取りたいすべての通貨capabilitiesを追加することで、この問題を部分的に解決することができます。`FungibleTokenSwitchboard`の詳細については、[Fungible Token Switchboard](https://github.com/onflow/flow-ft#fungible-token-switchboard)を参照してください。
<h1>Enabling creator royalties for NFTs</h1>

`NFTStorefrontV2`コントラクトは、オプションとして、NFTの最初の販売後にそのNFTの二次販売を行う場合の印税をミンターアカウントに支払うことをサポートしています。マーケットプレイスは、出品物の適格性を検証する際にクリエイターの印税をサポートするかどうかを独自に決定しています。私たちは、すべてのマーケットプレイスがクリエイターの印税をサポートし、**FLOW**エコシステム内のコミュニティのクリエイターをサポートすることを推奨します。

売り手のNFTが[Royalty Metadata View](https://github.com/onflow/flow-nft/blob/21c254438910c8a4b5843beda3df20e4e2559625/contracts/MetadataViews.cdc#L335)標準(standard)をサポートしている場合、マーケットプレイスは購入と同時にロイヤリティの支払いを履行することができます。`NFTStorefrontV2`は、出品の作成時に支払われるべきロイヤリティを動的に計算し、購入時の出品物のsaleCutとして適用します。
```ruby
/* Check whether the NFT implements the MetadataResolver or not. */
if nft.getViews().contains(Type<MetadataViews.Royalties>()) {
	/* Resolve the royalty view */
    let royaltiesRef = nft.resolveView(Type<MetadataViews.Royalties>())
        ?? panic("Unable to retrieve the royalties view for the NFT with type "
           .concat(nft.getType().identifier).concat(" and ID ")
           .concat(nft.id.toString()).concat(".")
	/* Fetch the royalties. */
	let royalties = (royaltiesRef as! MetadataViews.Royalties).getRoyalties()

	/* Append the royalties as the salecut */
    for royalty in royalties {
        self.saleCuts.append(NFTStorefrontV2.SaleCut(receiver: royalty.receiver, amount: royalty.cut * effectiveSaleItemPrice))
        totalRoyaltyCut = totalRoyaltyCut + royalty.cut * effectiveSaleItemPrice
    }
}
```
トランザクションの全内容は、[sell_item](https://github.com/onflow/nft-storefront/blob/main/transactions/sell_item.cdc) で確認できます。

saleCut は単一のトークンreceiver型のみをサポートしているため、`saleCut` の受益者は購入に使用されたトークン型のみを受け取ることができます。saleCuts で異なるトークン型をサポートするには、[`FungibleTokenSwitchboard`](https://github.com/onflow/flow-ft/blob/master/contracts/FungibleTokenSwitchboard.cdc) スマートコントラクトの使用をお勧めします。このコントラクトは、fungible トークン用の汎用receiverを定義し、そのトークン型に応じたそれぞれのvaultへのトークンのルーティングを処理します。詳細については、[Fungible Token Switchboard](https://github.com/onflow/flow-ft#fungible-token-switchboard) を参照してください。

<h1>Enabling marketplace commissions for NFT sales</h1>

`NFTStorefrontV2`は、NFTを販売用にリスティングすることの条件として取引手数料を必要とするマーケットプレイス向けに、取引手数料を任意で設定することができます。手数料および手数料receiverは、最初の出品作成時に販売者によってセットされます。購入と同時に、手数料の金額は、販売を円滑にしたマーケットプレイスの受取人(receiver)のアドレスに一致した手数料受取人(commission receiver)に一度だけ支払われます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3912821/d9ded6bc-b99f-a863-7fe6-49344c0e5b38.png)

<h1>APIs & Events offered by NFTStorefrontV2</h1>
<h2>Resource Interface ListingPublic</h2>

```ruby
resource interface ListingPublic {
    access(all) fun borrowNFT(): &NonFungibleToken.NFT?
    access(all) fun purchase(
          payment: @FungibleToken.Vault,
          commissionRecipient: Capability<&{FungibleToken.Receiver}>?,
      ): @NonFungibleToken.NFT
    access(all) fun getDetails(): ListingDetail
    access(all) fun getAllowedCommissionReceivers(): [Capability<&{FungibleToken.Receiver}>]?
}
```
Listingに便利なパブリックインターフェースを提供するインターフェース。
<h3>Functions</h3>

#### fun `borrowNFT()`
```ruby
fun borrowNFT(): &NonFungibleToken.NFT?
```
これは、NFTが存在しない場合、例えば別の出品で販売された場合など、NFT標準(standard)のborrowNFT()と同じ方法でアサート(assert)されます。
***
#### fun `purchase()`
```ruby
fun purchase(payment FungibleToken.Vault, commissionRecipient Capability<&{FungibleToken.Receiver}>?): NonFungibleToken.NFT
```
出品にゼロ以外の手数料が設定されている場合、支払いvaultと手数料(commission) recipient capabilityを提供することで、出品物の購入を円滑にします。それぞれのsaleCutsは受益者に送金され、関数は出品された対象のNFTを返します。
***
#### fun `getDetails()`
```ruby
fun getDetails(): ListingDetails
```
出品物の詳細を取得します
***
#### fun `getAllowedCommissionReceivers()`
```ruby
fun getAllowedCommissionReceivers(): [Capability<&{FungibleToken.Receiver}>]?
```
許可されているマーケットプレイスのCapabilityまたは対象の出品物の手数料receiverを取得します。`nil` が返された場合、その手数料は誰でも取得できます。

<h2>Resource Storefront</h2>

```ruby
resource Storefront {
    access(all) 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
    access(all) fun removeListing(listingResourceID: UInt64)
    access(all) fun getListingIDs(): [UInt64]
    access(all) fun getDuplicateListingIDs(nftType: Type, nftID: UInt64, listingID: UInt64): [UInt64]
    access(all) fun cleanupExpiredListings(fromIndex: UInt64, toIndex: UInt64)
    access(all) fun borrowListing(listingResourceID: UInt64): &Listing{ListingPublic}?
}
```
リソース所有者がListingsの一覧を管理したり、誰もがそれらの詳細を照会(query)したり、NFTを購入したりするためにListingsとやりとりすることを可能にするリソース。

実装されているインターフェイス：
* `StorefrontManager`
* `StorefrontPublic`

<h3>Initializer</h3>

```ruby
fun init()
```
<h3>Functions</h3>

#### fun `createListing()`
```ruby
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
```
***
#### fun `removeListing()`
```ruby
fun removeListing(listingResourceID UInt64)
```
removeListingは コレクションからまだ購入されていないListingを削除し、破棄します。
***
#### fun `getListingIDs()`
```ruby
fun getListingIDs(): [UInt64]
```
getListingIDsはコレクションに含まれるListingリソースIDの配列を返します。
***
#### fun `getDuplicateListingIDs()`
```ruby
fun getDuplicateListingIDs(nftType Type, nftID UInt64, listingID UInt64): [UInt64]
```
getDuplicateListingIDsは指定された`nftType`および`nftID`の(異なるマーケットプレイスで)重複している出品IDの配列を返します。
***
#### fun `cleanupExpiredListings()`
```ruby
fun cleanupExpiredListings(fromIndex UInt64, toIndex UInt64)
```
cleanupExpiredListingsは指定されたインデックス範囲を反復処理して、有効期限の切れた出品をクリーンアップします。
***
#### fun `borrowListing()`
```ruby
fun borrowListing(listingResourceID: UInt64): &{ListingPublic}?
```
borrowListingは指定の listingID がこのコレクションに含まれている場合、出品物の読み取り専用viewを返します。
<h2>Resource Interface StorefrontPublic</h2>

```ruby
resource interface StorefrontPublic {
    access(all) fun getListingIDs(): [UInt64]
    access(all) fun getDuplicateListingIDs(nftType: Type, nftID: UInt64, listingID: UInt64): [UInt64]
    access(all) fun cleanupExpiredListings(fromIndex: UInt64, toIndex: UInt64)
    access(all) fun borrowListing(listingResourceID: UInt64): &Listing{ListingPublic}?
    access(all) fun cleanupPurchasedListings(listingResourceID: UInt64)
    access(all) fun getExistingListingIDs(nftType: Type, nftID: UInt64): [UInt64]
}
```
StorefrontPublic: 出品やListingsの借用、StorefrontのListings経由での商品購入を可能にするインターフェース。

<h3>Functions</h3>

#### fun `getListingIDs()`
```ruby
fun getListingIDs(): [UInt64]
```
getListingIDsはコレクションに含まれるListingリソースIDの配列を返します。
***
#### fun `getDuplicateListingIDs()`
```ruby
fun getDuplicateListingIDs(nftType Type, nftID UInt64, listingID UInt64): [UInt64]
```
getDuplicateListingIDsは指定されたnftTypeとnftIDの(異なるマーケットプレイスで)重複している出品IDの配列を返します。
***
#### fun `borrowListing()`
```ruby
fun borrowListing(listingResourceID UInt64): &Listing{ListingPublic}?
```
borrowListingは指定の listingIDがこのコレクションに含まれている場合、出品物の読み取り専用viewを返します。
***
#### fun `cleanupExpiredListings()`
```ruby
fun cleanupExpiredListings(fromIndex UInt64, toIndex UInt64)
```
cleanupExpiredListingsは指定されたインデックス範囲を反復処理して、有効期限の切れた出品をクリーンアップします。
***
#### fun `cleanupPurchasedListings()`
```ruby
fun cleanupPurchasedListings(listingResourceID: UInt64)
```
cleanupPurchasedListingsは購入済みの出品物を誰でも削除できるようにします。
***
#### fun `getExistingListingIDs()`
```ruby
fun getExistingListingIDs(nftType Type, nftID UInt64): [UInt64]
```
getExistingListingIDsは指定した`nftType`および`nftID`の出品IDの配列を返します。
<h3>Events</h3>

#### event `StorefrontInitialized`
```ruby
event StorefrontInitialized(storefrontResourceID: UInt64)
```
Storefrontのリソースが作成されました。消費者はこのStorefrontからイベントを期待できるようになりました。 私たちはアドレスを指定しないことにご注意ください。私たちは指定できませんし、指定すべきではありません。作成されたリソースにはownerアドレスがないので、作成後に私たちが確認できない方法で移動される可能性もあります。`ListingAvailable`イベントは、出品の時点でのStorefrontのオーナー(owner)のアドレスを特定するために使用できますが、そのトランザクションのその瞬間に対してに限られます。出品が有効な間にStorefrontが移動された場合、その責任は売り手(Storefrontを移動したアカウント)側にあります。
***
**event `StorefrontDestroyed`**
```ruby
event StorefrontDestroyed(storefrontResourceID: UInt64)
```
Storefrontが破棄(destroyed)されました。イベントの消費者は、このStorefrontからのイベントを処理することを停止できます。Note：私たちはアドレスは特定しません。
***
#### event `ListingAvailable`
```ruby
event ListingAvailable(storefrontAddress: Address, listingResourceID: UInt64, nftType: Type, nftUUID: UInt64, nftID: UInt64, salePaymentVaultType: Type, salePrice: UFix64, customID: String?, commissionAmount: UFix64, commissionReceivers: [Address]?, expiry: UInt64)
```
このイベントは、出品が作成され、Storefrontリソースに追加された際に発行されます。このイベントが発行された時点では、Addressの値は有効ですが、参照しているアカウントのステートは`NFTStorefrontV2`のワークフロー外で変更されるかもしれないため、このアドレスを使用する際には注意が必要です。
***
#### event `ListingCompleted`
```ruby
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)
```
出品は解決済み(resolved)です。購入、削除、破棄のいずれかがなされました。
***
#### event `UnpaidReceiver`
```ruby
event UnpaidReceiver(receiver: Address, entitledSaleCut: UFix64)
```
NFTの売却中に、受取権を有する受取人に支払いがなされていない。

**Holistic process flow diagram of NFTStorefrontV2 -**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3912821/a92bc987-4b61-2ee6-56b1-71804ffe408b.png)


*Last updated on **Dec 11, 2024** by **Chase Fleming***

翻訳元

https://developers.flow.com/build/core-contracts/nft-storefront

***


<b>[Previous << NFT Metadata](https://qiita.com/flowcadence/items/191e2e765391e636a89c)
</b>

[Flow blockchain / Cadence version1.0ドキュメント](https://qiita.com/abcdefgac153131/items/3073d69c6e9895e68b5a) (NFT Storefront)

<b>[Next >> Staking Collection](https://qiita.com/flowcadence/items/89d155bb9a803da06b45)</b>