Skip to main content
Version: 1.0

7. Marketplace Setup

In this tutorial, we're going to create a marketplace that uses both the fungible and non-fungible token (NFTs) contracts that we have learned about in previous tutorials. This page requires you to execute a series of transactions to setup your accounts to complete the Marketplace tutorial. The next page contains the main content of the tutorial.

When you are done with the tutorial, check out the NFTStorefront repo for an example of a production ready marketplace that you can use right now on testnet or mainnet!


tip

Open the starter code for this tutorial in the Flow Playground:

https://play.onflow.org/49ec2856-1258-4675-bac3-850b4bae1929

The tutorial will be asking you to take various actions to interact with this code.

info

The playground code that is linked uses Cadence 0.42, but the examples use Cadence 1.0 to show how each contract, transaction and script is implemented in Cadence 1.0. You can access a Cadence 1.0-compatible playground by going to https://v1.play.flow.com/. The project link will still work with the current version of the playground, but when the playground is updated to Cadence 1.0, the link will be replaced with a 1.0-compatible version.

If you have already completed the Marketplace tutorial, please move on to Composable Resources: Kitty Hats.

This guide will help you quickly get the playground to the state you need to complete the Marketplace tutorial. The marketplace tutorial uses the Fungible Token and Non-Fungible token contracts to allow users to buy and sell NFTs with fungible tokens.

The state of the accounts is the same as if you had completed the Fungible Token and Non-Fungible Token tutorials in the same playground session. Having your playground in this state is necessary to follow the Composable Smart Contracts: Marketplace tutorial.


  1. Open account 0x01. Make sure the Fungible Token definitions in ExampleToken.cdc from the fungible token tutorial are in this account.
  2. Deploy the ExampleToken code to account 0x01.
  3. Switch to the ExampleNFT contract (Contract 2)
  4. Make sure you have the NFT definitions in ExampleNFT.cdc from the Non-fungible token tutorial in account 0x02.
  5. Deploy the NFT code to account 0x02 by selecting it as the deploying signer.
  6. Run the transaction in Transaction 1. This is the SetupAccount1Transaction.cdc file. Use account 0x01 as the only signer to set up account 0x01's storage.
SetupAccount1Transaction.cdc

_25
// SetupAccount1Transaction.cdc
_25
_25
import ExampleToken from 0x01
_25
import ExampleNFT from 0x02
_25
_25
// This transaction sets up account 0x01 for the marketplace tutorial
_25
// by publishing a Vault reference and creating an empty NFT Collection.
_25
transaction {
_25
prepare(acct: auth(SaveValue, StorageCapabilities) &Account) {
_25
// Create a public Receiver capability to the Vault
_25
let receiverCap = acct.capabilities.storage.issue<&{ExampleToken.Receiver}>(
_25
/storage/CadenceFungibleTokenTutorialVault
_25
)
_25
acct.capabilities.publish(receiverCap, at: /public/CadenceFungibleTokenTutorialReceiver)
_25
_25
// store the empty NFT Collection in account storage
_25
acct.storage.save(<-ExampleNFT.createEmptyCollection(nftType: nil), to: ExampleNFT.CollectionStoragePath)
_25
_25
log("Collection created for account 2")
_25
_25
// create a public capability for the Collection
_25
let cap = acct.capabilities.storage.issue<&{ExampleNFT.NFTReceiver}>(ExampleNFT.CollectionStoragePath)
_25
acct.capabilities.publish(cap, at: ExampleNFT.CollectionPublicPath)
_25
}
_25
}

  1. Run the transaction in Transaction 2. This is the SetupAccount2Transaction.cdc file. Use account 0x02 as the only signer to set up account 0x02's storage.
SetupAccount2Transaction.cdc

_44
// SetupAccount2Transaction.cdc
_44
_44
import ExampleToken from 0x01
_44
import ExampleNFT from 0x02
_44
_44
// This transaction adds an empty Vault to account 0x02
_44
// and mints an NFT with id=1 that is deposited into
_44
// the NFT collection on account 0x01.
_44
transaction {
_44
_44
// Private reference to this account's minter resource
_44
let minterRef: &ExampleNFT.NFTMinter
_44
_44
prepare(acct: auth(SaveValue, StorageCapabilities, BorrowValue) &Account) {
_44
// create a new vault instance with an initial balance of 30
_44
let vaultA <- ExampleToken.createEmptyVault()
_44
_44
// Store the vault in the account storage
_44
acct.storage.save(<-vaultA, to: /storage/CadenceFungibleTokenTutorialVault)
_44
_44
// Create a public Receiver capability to the Vault
_44
let receiverCap = acct.capabilities.storage.issue<&{ExampleToken.Receiver}>(
_44
/storage/CadenceFungibleTokenTutorialVault
_44
)
_44
acct.capabilities.publish(receiverCap, at: /public/CadenceFungibleTokenTutorialReceiver)
_44
_44
// Borrow a reference for the NFTMinter in storage
_44
self.minterRef = acct.storage.borrow<&ExampleNFT.NFTMinter>(from: ExampleNFT.MinterStoragePath)
_44
?? panic("Could not borrow owner's NFT minter reference")
_44
}
_44
execute {
_44
// Get the recipient's public account object
_44
let recipient = getAccount(0x01)
_44
_44
// Get the Collection reference for the receiver
_44
// getting the public capability and borrowing a reference from it
_44
let receiverRef = recipient.capabilities
_44
.borrow<&{ExampleNFT.NFTReceiver}>(ExampleNFT.CollectionPublicPath)
_44
?? panic("Could not borrow receiver reference")
_44
_44
// Mint an NFT and deposit it into account 0x01's collection
_44
receiverRef.deposit(token: <-self.minterRef.mintNFT())
_44
}
_44
}

  1. Run the transaction in Transaction 3. This is the SetupAccount1TransactionMinting.cdc file. Use account 0x01 as the only signer to mint fungible tokens for account 1 and 2.
SetupAccount1TransactionMinting.cdc

_35
// SetupAccount1TransactionMinting.cdc
_35
_35
import ExampleToken from 0x01
_35
import ExampleNFT from 0x02
_35
_35
// This transaction mints tokens for both accounts using
_35
// the minter stored on account 0x01.
_35
transaction {
_35
_35
// Public Vault Receiver References for both accounts
_35
let acct1Capability: Capability<&AnyResource{ExampleToken.Receiver}>
_35
let acct2Capability: Capability<&AnyResource{ExampleToken.Receiver}>
_35
_35
// Private minter references for this account to mint tokens
_35
let minterRef: &ExampleToken.VaultMinter
_35
_35
prepare(acct: auth(SaveValue, StorageCapabilities, BorrowValue) &Account) {
_35
// Get the public object for account 0x02
_35
let account2 = getAccount(0x02)
_35
_35
// Retrieve public Vault Receiver references for both accounts
_35
self.acct1Capability = acct.capabilities.get<&{ExampleToken.Receiver}>(/public/CadenceFungibleTokenTutorialReceiver)
_35
self.acct2Capability = account2.capabilities.get<&{ExampleToken.Receiver}>(/public/CadenceFungibleTokenTutorialReceiver)
_35
_35
// Get the stored Minter reference for account 0x01
_35
self.minterRef = acct.storage.borrow<&ExampleToken.VaultMinter>(from: /storage/CadenceFungibleTokenTutorialMinter)
_35
?? panic("Could not borrow owner's vault minter reference")
_35
}
_35
_35
execute {
_35
// Mint tokens for both accounts
_35
self.minterRef.mintTokens(amount: 20.0, recipient: self.acct2Capability)
_35
self.minterRef.mintTokens(amount: 10.0, recipient: self.acct1Capability)
_35
}
_35
}

  1. Run the script CheckSetupScript.cdc file in Script 1 to ensure everything is set up.
CheckSetupScript.cdc

_73
// CheckSetupScript.cdc
_73
_73
import ExampleToken from 0x01
_73
import ExampleNFT from 0x02
_73
_73
/// Allows the script to return the ownership info
_73
/// of all the accounts
_73
access(all) struct OwnerInfo {
_73
access(all) let acct1Balance: UFix64
_73
access(all) let acct2Balance: UFix64
_73
_73
access(all) let acct1IDs: [UInt64]
_73
access(all) let acct2IDs: [UInt64]
_73
_73
init(balance1: UFix64, balance2: UFix64, acct1IDs: [UInt64], acct2IDs: [UInt64]) {
_73
self.acct1Balance = balance1
_73
self.acct2Balance = balance2
_73
self.acct1IDs = acct1IDs
_73
self.acct2IDs = acct2IDs
_73
}
_73
}
_73
_73
// This script checks that the accounts are set up correctly for the marketplace tutorial.
_73
//
_73
// Account 0x01: Vault Balance = 40, NFT.id = 1
_73
// Account 0x02: Vault Balance = 20, No NFTs
_73
access(all) fun main(): OwnerInfo {
_73
// Get the accounts' public account objects
_73
let acct1 = getAccount(0x01)
_73
let acct2 = getAccount(0x02)
_73
_73
// Get references to the account's receivers
_73
// by getting their public capability
_73
// and borrowing a reference from the capability
_73
let acct1ReceiverRef = acct1.capabilities.get<&{ExampleToken.Balance}>
_73
(/public/CadenceFungibleTokenTutorialReceiver)
_73
.borrow()
_73
?? panic("Could not borrow acct1 vault reference")
_73
_73
let acct2ReceiverRef = acct2.capabilities.get<&{ExampleToken.Balance}>
_73
(/public/CadenceFungibleTokenTutorialReceiver)
_73
.borrow()
_73
?? panic("Could not borrow acct2 vault reference")
_73
_73
let returnArray: [UFix64] = []
_73
_73
// verify that the balances are correct
_73
if acct1ReceiverRef.balance != 40.0 || acct2ReceiverRef.balance != 20.0 {
_73
panic("Wrong balances!")
_73
}
_73
_73
// Find the public Receiver capability for their Collections
_73
let acct1Capability = acct1.capabilities.get<&{ExampleNFT.NFTReceiver}>(ExampleNFT.CollectionPublicPath)
_73
let acct2Capability = acct2.capabilities.get<&{ExampleNFT.NFTReceiver}>(ExampleNFT.CollectionPublicPath)
_73
_73
// borrow references from the capabilities
_73
let nft1Ref = acct1Capability.borrow()
_73
?? panic("Could not borrow acct1 nft collection reference")
_73
_73
let nft2Ref = acct2Capability.borrow()
_73
?? panic("Could not borrow acct2 nft collection reference")
_73
_73
// verify that the collections are correct
_73
if nft1Ref.getIDs()[0] != 1 || nft2Ref.getIDs().length != 0 {
_73
panic("Wrong Collections!")
_73
}
_73
_73
// Return the struct that shows the account ownership info
_73
return OwnerInfo(balance1: acct1ReceiverRef.balance,
_73
balance2: acct2ReceiverRef.balance,
_73
acct1IDs: nft1Ref.getIDs(),
_73
acct2IDs: nft2Ref.getIDs())
_73
}

  1. The script should not panic and you should see something like this output

_10
"Account 1 Balance"
_10
40.00000000
_10
"Account 2 Balance"
_10
20.00000000
_10
"Account 1 NFTs"
_10
[1]
_10
"Account 2 NFTs"
_10
[]


With your playground now in the correct state, you're ready to continue with the next tutorial.

You do not need to open a new playground session for the marketplace tutorial. You can just continue using this one.