Previous << NFT Metadata
Next >> Staking Collection
NFTStorefront
のスマートコントラクトは、NFTを販売用にリストアップし、そのリストから購入するための標準的な方法を実装しています。NFTStorefrontV2
はより強力で機能が豊富なバージョンであるため、開発者およびユーザーはNFTStorefront
または独自の実装ではなく、こちらを使用することをお勧めします。
Source: NFTStorefrontV2.cdc
Network | Contract Address |
---|---|
Testnet | 0x2d55b98eb200daef |
Mainnet | 0x4eb8a10cb9f87357 |
Source: NFTStorefront.cdc
Network | Contract Address |
---|---|
Testnet | 0x94b06cfca1d8a476 |
Mainnet | 0x4eb8a10cb9f87357 |
Primer
NFTStorefrontV2
スマートコントラクトにより、FLOWブロックチェーン上で非管理型(non-custodial)リソース(NFT)マーケットプレイス を作成することができます。
NFTStorefrontV2
により、販売者はdApp専用マーケットプレイスにNFTを簡単にリストアップすることができます。dApp開発者は、このコントラクトが提供するAPIを活用して、販売中のリストを管理し、NFT取引を行うことができます。
開発者はNFTStorefrontV2
を使用して、マーケットプレイスを作成し、ピアツーピアでの購入を可能にすべきです。以下の図は、dAppsが異なるマーケットプレイスにおけるNFTの出品を円滑にする方法と、マーケットプレイスが出品をフィルタリングする方法を示しています。
特定のdAppストアフロント(storefront)を通じて作成された出品は、そのdAppの枠を超えてサードパーティのマーケットプレイスにも同時に出品することができます。よく知られたサードパーティのマーケットプレイスは、互換性のあるNFT出品イベントを監視しており、それらのマーケットプレイスのダッシュボードへの出品の自動化を可能にしています。
NFTStorefrontV2
を使用することで、マーケットプレイスは活気のあるFLOW NFTエコシステムに対して、即座かつ簡単にアクセスでき、NFT保有者がNFTを出品できるようにし、クリエイターのロイヤリティを可能にします。
マーケットプレイスは、売り手のストアフロントと直接やりとりすることで、NFT取引を処理します。Flowのアカウントベースのモデルでは、同じNFTが複数のマーケットプレイスにいくつ掲載されていても、NFTが取引されるまで、売り手のアカウントに常に存在することが保証されます。
Functional Overview
Flow NonFungibleToken
標準(standard)を実装した、 NFT の汎用的販売サポートコントラクト。NFT を販売したい各アカウントは、Storefront
リソースを作成し、アカウント内に保存します。その Storefront 内にListings として、個々の販売を リスティングします。通常、アカウントごとに 1 つの /storage/NFTStorefrontV2
に保持されたStorefront があります。
各出品では、販売価格から差し引かれる1つまたは複数の販売カット(補足: =サービス手数料)を、1つまたは複数のアドレスに送るように定義できます。出品手数料、ロイヤリティ、またはその他の対価は、販売カットを使用して支払うことができます。また、出品には、購入を促進した人物に対して支払われる、販売カットの1つの手数料を含めることができます。
出品には、出品を履行したことに対する手数料を受け取るための、任意のマーケットプレイス receiver capabilities のリストを持つことができます。NFTは1つ以上のListingsに出品することができ、各出品の有効性は簡単に確認できます。
関係者は、オンチェーンで出品イベントをグローバルに追跡し、NFTタイプ、ID、その他の特性でフィルタリングして、彼ら自身のマーケットプレイスUI内で、購入可能にするものをどれにするか決定することができます。
Selling NFTs
NFTStorefrontV2
は、NFTの出品を作成するための一般的なプロセスを提供します。出品を個別に管理するためのすべての必須APIを提供します。
多くのマーケットプレイスでは、異なる個々の出品を管理するために単一のストアフロントリソースを作成します。信頼性が高く、プラットフォームに依存しないように、ユーザー所有のストアフロントリソースの下に出品を作成することをお勧めします。ユーザーは、ストアフロント スマートコントラクトを使用して出品を作成するために、アカウントの下にStorefront
リソースを保有する必要があります。
Creating a successful listing using the NFTStorefrontV2 contract.
上記で推奨したように、ファーストステップは、setup_account トランザクションを使用して、Storefrontリソースを作成してユーザーアカウント内に保存することです。
次のステップは、新しく作成したStorefrontリソースの下にlisting(出品)を作成することです。ユーザーがすでにStorefrontリソースを保持している場合は、既存のリソースを使用します。売り手は、NFTを出品するために複数の要件を提示できます。そして、私たちはそれらのほとんどをカバーするために、下に書かれているように最善を尽くしています。
Scenario 1: Selling NFTs corresponds to more than one cryptocurrency, i.e. FLOW, USDC etc.
NFTStorefrontV2
スマートコントラクトでは、1回の出品で複数の異なる通貨によるNFTの販売をサポートしていません。しかし、これは、異なる通貨ごとに同じNFTの複数の出品を作成することで実現できます。
Example - アリスは(デジタルの)子猫を売りたいと思っており、FLOWとUSDCを受け取ることに前向きである。(補足: 子猫が登場するのはFlow作者がCryptoKittiesの作者だからです)
NFTを販売することを「出品」と呼び、売り手はNFTを出品するためにsell_itemトランザクションを使用して、必要な詳細情報を提供することにより、出品を作成することができます。例えば、受け取り通貨の種類、NFTが差し引かれるCapabilityなどです。興味のある方は、createListing
にて詳細をご覧ください。
異なる通貨を受け取るためには、売り手は異なるReceiver currency type、すなわちsalePaymentVaultType
を提供する必要があります。上記の図に示されているように、ほぼ同じ入力で2つの出品フォームがあります。唯一の違いは、salePaymentVaultType
パラメータであり、異なる販売通貨タイプで重複するNFT出品を作成する場合は、異なる値にする必要があります。
Scenario 2: Peer-to-Peer (p2p) listing of NFT: A listing anyone can fulfil.
DappsはNFTStorefrontV2を活用して、マーケットプレイスとは独立した形で販売者の出品を促進することができます。Dappsやマーケットプレイスは、それらの出品をそれぞれのプラットフォームに掲載することができます。または、販売者がピアツーピアで決済することも可能です。
売り手は、p2pの出品を作成するためにsell_itemトランザクションを使用して、marketplacesAddress
に空の配列を指定します。売り手は、販売の仲介者にcommission(手数料)を支払うかどうかの選択肢があり、仲介者と購入者が同一の場合は、手数料を割引として適用することもできます。
Scenario 3: The seller wants to list its NFT in different marketplaces.
NFTStorefrontV2
では、2つの異なる方法を提供しています。
- 売り手は、出品を作成し、sell_item トランザクションを使用して、これから出品を希望する
marketplacesAddress
を提供することができます。
マーケットプレイスは、ListingAvailable
イベントを監視し、commissionReceivers
リストに自身のアドレスが含まれているかどうかを確認することができます。出品が成功裏に完了した際に報酬が支払われることになります。
Example - ボブはマーケットプレイス0xA、0xB、0xCに出品したいと考えており、出品の販売価格の10%をマーケットプレイスに手数料として提供する意思があります。
- もう一つの方法は、sell_item_with_marketplace_cut トランザクションを使用して、ユーザーが自分の出品を希望する各マーケットプレイスに対して個別の出品を作成することです。この場合、マーケットプレイスは、出品の作成時に
saleCuts
配列にmarketplace saleCutを追加することで、saleCut
の1部を獲得することでインセンティブを得ることができます。
Considerations
-
ゴースト出品 - ゴースト出品とは、売り手のアカウントにNFTが存在しない出品のことです。ただし、その出品は購入者が購入を試みることは可能です。StorefrontV2はゴースト出品を完全に排除できるわけではありません。通常、ゴースト出品は購入者のトランザクションを失敗させますが、これは厄介ではあるものの、重大な問題ではありません。ゴースト出品が売り手にとって問題となるのは、出品されたNFTが最初の販売後に売り手のアカウントに戻ってきた場合です。ゴースト出品は、戻ってきた時点で無効ではなくなり、売り手がその価格で販売したくない場合でも、誰でも購入することができます。
Note - マーケットプレイスやピアツーピアのdAppsは、ユーザー(つまり売り手)がNFTを同じアカウントで保有していない場合は出品を削除するよう伝えるオフチェーン通知サービスを作成することをお勧めします。 -
期限切れの出品 -
NFTStorefrontV2
では、出品が作成時に設定できる一定期間後に期限切れとなり、誰も購入できなくなるという安全対策が導入されています。これは完璧な安全対策ではありませんが、ゴースト出品や期限切れ出品に対する売り手の安全対策にはなります。
Note - マーケットプレイスやピアツーピアの分散型アプリケーションでは、期限切れのリストをダッシュボードに表示しないことを推奨します。
Purchasing NFTs
NFTStorefrontV2
を通じて NFT を購入するのは簡単です。購入者は購入時に、支払いVaultと、必要に応じてcommissionRecipient
を提供する必要があります。p2p dApps では、出品の購入を仲介する第三者は必要ありません。Listing
リソースによって提供される purchase
API を使用して、NFT の購入が実行されます。
出品物の購入時には、すべてのsaleCutsが(関係各所に)自動的に支払われます。これには、該当する場合、そのNFTのロイヤリティの分配も含まれます。購入者が提供したvaultに十分な資金がない場合、トランザクションは失敗します。
Considerations
-
自動クリーンアップ -
NFTStorefrontV2
は、購入中に重複した出品を自動的にクリーンアップするユニークな機能を提供します。 但し、それは1つのNFTに数千の(異なるマーケットプレイスに)重複した出品がある場合、欠点があります。 ガス不足エラーが発生する可能性が高いため、出品のいずれかを購入する際のボトルネックとなります。
Note - 任意のNFTの重複出品は50(未定)を超えないことをお勧めします。 -
サポートされていないreceiver capability - NFTの購入時にありがちな落とし穴として、一部のsaleCut receiverがサポートされていないreceiver capabilityを持っていることが挙げられます。これは、その権利あるsaleCutが最初に有効となったsale cut receiverに送金されるためです。しかし、
FungibleTokenSwitchboard
スマートコントラクトを使用して汎用receiverを提供し、受益者が受け取りたいすべての通貨capabilitiesを追加することで、この問題を部分的に解決することができます。FungibleTokenSwitchboard
の詳細については、Fungible Token Switchboardを参照してください。
Enabling creator royalties for NFTs
NFTStorefrontV2
コントラクトは、オプションとして、NFTの最初の販売後にそのNFTの二次販売を行う場合の印税をミンターアカウントに支払うことをサポートしています。マーケットプレイスは、出品物の適格性を検証する際にクリエイターの印税をサポートするかどうかを独自に決定しています。私たちは、すべてのマーケットプレイスがクリエイターの印税をサポートし、FLOWエコシステム内のコミュニティのクリエイターをサポートすることを推奨します。
売り手のNFTがRoyalty Metadata View標準(standard)をサポートしている場合、マーケットプレイスは購入と同時にロイヤリティの支払いを履行することができます。NFTStorefrontV2
は、出品の作成時に支払われるべきロイヤリティを動的に計算し、購入時の出品物のsaleCutとして適用します。
/* 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 で確認できます。
saleCut は単一のトークンreceiver型のみをサポートしているため、saleCut
の受益者は購入に使用されたトークン型のみを受け取ることができます。saleCuts で異なるトークン型をサポートするには、FungibleTokenSwitchboard
スマートコントラクトの使用をお勧めします。このコントラクトは、fungible トークン用の汎用receiverを定義し、そのトークン型に応じたそれぞれのvaultへのトークンのルーティングを処理します。詳細については、Fungible Token Switchboard を参照してください。
Enabling marketplace commissions for NFT sales
NFTStorefrontV2
は、NFTを販売用にリスティングすることの条件として取引手数料を必要とするマーケットプレイス向けに、取引手数料を任意で設定することができます。手数料および手数料receiverは、最初の出品作成時に販売者によってセットされます。購入と同時に、手数料の金額は、販売を円滑にしたマーケットプレイスの受取人(receiver)のアドレスに一致した手数料受取人(commission receiver)に一度だけ支払われます。
APIs & Events offered by NFTStorefrontV2
Resource Interface ListingPublic
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に便利なパブリックインターフェースを提供するインターフェース。
Functions
fun borrowNFT()
fun borrowNFT(): &NonFungibleToken.NFT?
これは、NFTが存在しない場合、例えば別の出品で販売された場合など、NFT標準(standard)のborrowNFT()と同じ方法でアサート(assert)されます。
fun purchase()
fun purchase(payment FungibleToken.Vault, commissionRecipient Capability<&{FungibleToken.Receiver}>?): NonFungibleToken.NFT
出品にゼロ以外の手数料が設定されている場合、支払いvaultと手数料(commission) recipient capabilityを提供することで、出品物の購入を円滑にします。それぞれのsaleCutsは受益者に送金され、関数は出品された対象のNFTを返します。
fun getDetails()
fun getDetails(): ListingDetails
出品物の詳細を取得します
fun getAllowedCommissionReceivers()
fun getAllowedCommissionReceivers(): [Capability<&{FungibleToken.Receiver}>]?
許可されているマーケットプレイスのCapabilityまたは対象の出品物の手数料receiverを取得します。nil
が返された場合、その手数料は誰でも取得できます。
Resource Storefront
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
Initializer
fun init()
Functions
fun createListing()
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()
fun removeListing(listingResourceID UInt64)
removeListingは コレクションからまだ購入されていないListingを削除し、破棄します。
fun getListingIDs()
fun getListingIDs(): [UInt64]
getListingIDsはコレクションに含まれるListingリソースIDの配列を返します。
fun getDuplicateListingIDs()
fun getDuplicateListingIDs(nftType Type, nftID UInt64, listingID UInt64): [UInt64]
getDuplicateListingIDsは指定されたnftType
およびnftID
の(異なるマーケットプレイスで)重複している出品IDの配列を返します。
fun cleanupExpiredListings()
fun cleanupExpiredListings(fromIndex UInt64, toIndex UInt64)
cleanupExpiredListingsは指定されたインデックス範囲を反復処理して、有効期限の切れた出品をクリーンアップします。
fun borrowListing()
fun borrowListing(listingResourceID: UInt64): &{ListingPublic}?
borrowListingは指定の listingID がこのコレクションに含まれている場合、出品物の読み取り専用viewを返します。
Resource Interface StorefrontPublic
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経由での商品購入を可能にするインターフェース。
Functions
fun getListingIDs()
fun getListingIDs(): [UInt64]
getListingIDsはコレクションに含まれるListingリソースIDの配列を返します。
fun getDuplicateListingIDs()
fun getDuplicateListingIDs(nftType Type, nftID UInt64, listingID UInt64): [UInt64]
getDuplicateListingIDsは指定されたnftTypeとnftIDの(異なるマーケットプレイスで)重複している出品IDの配列を返します。
fun borrowListing()
fun borrowListing(listingResourceID UInt64): &Listing{ListingPublic}?
borrowListingは指定の listingIDがこのコレクションに含まれている場合、出品物の読み取り専用viewを返します。
fun cleanupExpiredListings()
fun cleanupExpiredListings(fromIndex UInt64, toIndex UInt64)
cleanupExpiredListingsは指定されたインデックス範囲を反復処理して、有効期限の切れた出品をクリーンアップします。
fun cleanupPurchasedListings()
fun cleanupPurchasedListings(listingResourceID: UInt64)
cleanupPurchasedListingsは購入済みの出品物を誰でも削除できるようにします。
fun getExistingListingIDs()
fun getExistingListingIDs(nftType Type, nftID UInt64): [UInt64]
getExistingListingIDsは指定したnftType
およびnftID
の出品IDの配列を返します。
Events
event StorefrontInitialized
event StorefrontInitialized(storefrontResourceID: UInt64)
Storefrontのリソースが作成されました。消費者はこのStorefrontからイベントを期待できるようになりました。 私たちはアドレスを指定しないことにご注意ください。私たちは指定できませんし、指定すべきではありません。作成されたリソースにはownerアドレスがないので、作成後に私たちが確認できない方法で移動される可能性もあります。ListingAvailable
イベントは、出品の時点でのStorefrontのオーナー(owner)のアドレスを特定するために使用できますが、そのトランザクションのその瞬間に対してに限られます。出品が有効な間にStorefrontが移動された場合、その責任は売り手(Storefrontを移動したアカウント)側にあります。
event StorefrontDestroyed
event StorefrontDestroyed(storefrontResourceID: UInt64)
Storefrontが破棄(destroyed)されました。イベントの消費者は、このStorefrontからのイベントを処理することを停止できます。Note:私たちはアドレスは特定しません。
event ListingAvailable
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
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
event UnpaidReceiver(receiver: Address, entitledSaleCut: UFix64)
NFTの売却中に、受取権を有する受取人に支払いがなされていない。
Holistic process flow diagram of NFTStorefrontV2 -
Last updated on Dec 11, 2024 by Chase Fleming
翻訳元
Flow BlockchainのCadence version1.0ドキュメント (NFT Storefront)