Purchase NFT on Marketplace
Purchase NFT on Marketplace
01 Apr 2022
Contributed by Flow Blockchain
Buy an NFT from a marketplace.
Smart Contract Example
When purchasing an NFT, the purchaser needs only to provide their payment in the form of a vault resource. The smart contract then verifies that the listing has not already been purchased, ensuring the fungible token provided matches the required type for the transaction and that the payment amount is correct.
If all these conditions are met, the purchase is approved, and the listing status is updated to reflect the purchase. The contract withdraws the NFT from the seller's account and verifies that it is the correct type and ID, ensuring the purchased NFT is the one intended. Once confirmed, the contract calculates the sales cuts and begins depositing the respective amounts into the vault receivers of the designated accounts using pre-established capabilities. Any remaining funds are transferred into a residual receiver, which acts as a container for the leftover payment vault, with its balance reduced to zero by this process.
Finally, the transaction is completed by emitting an event signaling its success, and the NFT is returned to the purchaser, allowing them to deposit it into their collection.
Transaction Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import "FungibleToken"
import "NonFungibleToken"
import "ExampleNFT"
import "NFTStorefrontV2"
transaction {
let paymentVault: @{FungibleToken.Vault}
let exampleNFTCollection: &ExampleNFT.Collection
let storefront: auth(NFTStorefrontV2.CreateListing) &NFTStorefrontV2.Storefront
let listing: &{NFTStorefrontV2.ListingPublic}
var listingResourceId: UInt64
prepare(acct: auth(Storage, Capabilities, NFTStorefrontV2.CreateListing) &Account) {
// Create and save the storefront
let storefront <- NFTStorefrontV2.createStorefront()
acct.storage.save(<-storefront, to: NFTStorefrontV2.StorefrontStoragePath)
// Publish the storefront capability to the public path
let storefrontCap = acct.capabilities.storage.issue<&{NFTStorefrontV2.StorefrontPublic}>(
NFTStorefrontV2.StorefrontStoragePath
)
acct.capabilities.publish(storefrontCap, at: NFTStorefrontV2.StorefrontPublicPath)
// Borrow the storefront reference using the public capability path
let storefrontRef = acct.capabilities.borrow<&{NFTStorefrontV2.StorefrontPublic}>(
NFTStorefrontV2.StorefrontPublicPath
) ?? panic("Could not borrow Storefront from provided address")
// Borrow the storefront reference directly from storage
self.storefront = acct.storage.borrow<auth(NFTStorefrontV2.CreateListing) &NFTStorefrontV2.Storefront>(
from: NFTStorefrontV2.StorefrontStoragePath
) ?? panic("Could not borrow Storefront with CreateListing authorization from storage")
// Borrow the NFTMinter from the caller's storage
let minter = acct.storage.borrow<&ExampleNFT.NFTMinter>(
from: /storage/exampleNFTMinter
) ?? panic("Could not borrow the NFT minter reference.")
// Mint a new NFT with metadata
let nft <- minter.mintNFT(
name: "Example NFT",
description: "Minting a sample NFT",
thumbnail: "https://example.com/thumbnail.png",
royalties: [],
metadata: {
"Power": "100",
"Will": "Strong",
"Determination": "Unyielding"
},
)
let nftID = nft.id
// Borrow the collection from the caller's storage
let collection = acct.storage.borrow<&ExampleNFT.Collection>(
from: /storage/exampleNFTCollection
) ?? panic("Could not borrow the NFT collection reference.")
// Deposit the newly minted NFT into the caller's collection
collection.deposit(token: <-nft)
let nftProviderCapability = acct.capabilities.storage.issue<auth(NonFungibleToken.Withdraw) &{NonFungibleToken.Collection}>(
/storage/exampleNFTCollection
)
// List the NFT
self.listingResourceId = self.storefront.createListing(
nftProviderCapability: nftProviderCapability,
nftType: Type<@ExampleNFT.NFT>(),
nftID: nftID,
salePaymentVaultType: Type<@{FungibleToken.Vault}>(),
saleCuts: [
NFTStorefrontV2.SaleCut(
receiver: acct.capabilities.get<&{FungibleToken.Receiver}>(
/public/flowTokenReceiver
)!,
amount: 1.0
)
],
marketplacesCapability: nil,
customID: nil,
commissionAmount: 0.0,
expiry: UInt64(getCurrentBlock().timestamp + UFix64(60 * 60 * 24))
)
log("Listing created successfully")
// Borrow the listing reference
self.listing = self.storefront.borrowListing(listingResourceID: self.listingResourceId)
?? panic("No Offer with that ID in Storefront")
// Fetch the sale price
let price = self.listing.getDetails().salePrice
// Issue the capability for the FlowToken vault with Withdraw entitlement
let flowTokenCap = acct.capabilities.storage.issue<auth(FungibleToken.Withdraw) &{FungibleToken.Vault}>(
/storage/flowTokenVault
)
// Withdraw the payment
let flowTokenVault = flowTokenCap.borrow()
?? panic("Failed to borrow FungibleToken.Vault from capability")
self.paymentVault <- flowTokenVault.withdraw(amount: price)
// Borrow the NFT collection receiver reference
let nftCollectionCap = acct.capabilities.borrow<&ExampleNFT.Collection>(
ExampleNFT.CollectionPublicPath
) ?? panic("Cannot borrow NFT collection receiver from account")
self.exampleNFTCollection = nftCollectionCap
}
execute {
// Execute the purchase
let item <- self.listing.purchase(
payment: <-self.paymentVault,
commissionRecipient: nil
)
// Confirm the token type and deposit the purchased NFT into the buyer's collection
let nft <- item as! @ExampleNFT.NFT
self.exampleNFTCollection.deposit(token: <-nft)
log("Transaction completed successfully")
}
}
This transaction begins by defining the expected types for the variables that will be returned during the process. The first step involves accessing the storefront associated with the account holding the desired listing. This storefront is publicly accessible via a linked capability, enabling others to interact with and purchase listings.
Once the storefront is borrowed, the transaction retrieves the specific listing of interest and assigns it to the listing variable. The price of the listing is then fetched, which allows the purchaser to prepare the appropriate payment. Using the price, the purchaser withdraws the required tokens from their Vault resource, ensuring they have the correct amount for the transaction. Additionally, the purchaser retrieves their Receiver capability, which will be used later to deposit the purchased NFT into their collection.
With these preparations complete, the purchaser invokes the purchase function on the listing, passing in their payment vault as the payment method. This action returns the NFT resource, which is temporarily stored in the item variable. The transaction then deposits the NFT into the purchaser's collection using their Receiver capability. Finally, it cleans up the storefront by deleting the completed listing, marking the successful completion of the purchase on the NFT marketplace.
100%