Cadence Cookbook

Contribute

Purchase NFT on Marketplace

Purchase NFT on Marketplace

01 Apr 2022

Contributed by Flow Blockchain

Intermediate

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.


ProgressNFT Storefront Essentials

100%


Related Recipes

14 Oct 2022
Create a Marketplace
Intermediate
14 Oct 2022
Create an NFT Listing
Intermediate