Skip to content

How to Build an NFT Marketplace DApp with thirdweb

by Kevin Neilson

thirdweb is a powerful development platform that simplifies building and deploying Web3 applications on the blockchain. It provides pre-built smart contracts and tools, enabling developers to quickly launch applications that interact with NFTs, tokens, and more with less coding and configuration effort.

In this guide, we'll go step by step through the process of building an NFT marketplace DApp with thirdweb on Moonbeam. We'll deploy all of the associated contracts, including an ERC-721 NFT contract and a marketplace smart contract to Moonbase Alpha with thirdweb, and then we'll integrate them into the DApp.

For a more nuts and bolts approach to thirdweb with information about available methods, the thirdweb CLI and deployment tools, be sure to check out the thirdweb guide in the Builders section.

Clone the Template

thirdweb has an NFT marketplace template that is a perfect starting point for our needs. We'll only need to make minor customizations to it. Please note, thirdweb frequently updates their templates and tutorials, so ensure that you're using the latest and greatest, which may be located in another repository.

  1. In your CLI run the following command:

    git clone https://github.com/thirdweb-example/marketplace-template
    
  2. Navigate to your project directory and install dependencies with your preferred package manager:

    npm install
    
    yarn
    
    pnpm install
    

Next, you'll need to create a client ID for your thirdweb project and specify it in a .env file.

Specify Client ID

Before you launch your dApp (locally or publicly deployed), you must have a thirdweb Client ID associated with your project. A thirdweb Client ID is synonymous with an API key. You can create a free API key by signing into your thirdweb account and navigating to Settings then click on API Keys.

Press Create API Key then take the following steps:

  1. Give your API key a name
  2. Enter the allowed domains that the API key should accept requests from. It's recommended that you allow only necessary domains, but for development purposes, you can select Allow all domains
  3. Press Next and confirm the prompt on the next page

thirdweb create API key

Now, create a file a called .env.local at the root level directory of your project. Add your Client ID as follows:

.env.local
NEXT_PUBLIC_TW_CLIENT_ID="INSERT_CLIENT_ID"

There are no other fields that you need to specify in your .env file at this time. If you're uncertain about formatting, you can refer to the .env.example file included in the project.

Run the project

We're not finished with the project yet, but it should be at a stage where you can launch the template and see the web app load successfully in your browser.

npm run dev
yarn dev
pnpm dev

If you see a blank screen, this typically means that you've failed to properly configure your client ID.

Add Support for Moonbase Alpha

thirdweb offers a small number of chains from @thirdweb/chains and does not include Moonbeam networks in that list, so you'll need to specify the network details including chain ID and RPC URL. You can create a custom chain with defineChain as follows:

chains.ts
import { defineChain } from 'thirdweb';
const moonbeam = defineChain({
  id: 1284,
  rpc: 'https://rpc.api.moonbeam.network',
});
chains.ts
import { defineChain } from 'thirdweb';
const moonriver = defineChain({
  id: 1285,
  rpc: 'https://rpc.api.moonriver.moonbeam.network',
});
chains.ts
import { defineChain } from 'thirdweb';
const moonbase = defineChain({
  id: 1287,
  rpc: 'https://rpc.api.moonbase.moonbeam.network',
});

The NFT marketplace template includes a chains.ts file under src/consts/chains.ts. To add support for Moonbase Alpha to the DApp, add the following lines:

chains.ts
export const moonbase = defineChain({
  id: 1287,
  rpc: 'https://rpc.api.moonbase.moonbeam.network',
});

We don't need to add any import statements because defineChain is already imported by default as part of the template. Feel free to add additional chains if you'd like to add support for Moonbeam, Moonriver, or other networks. The full file can be viewed below:

View chains.ts
import { defineChain } from 'thirdweb';

/**
 * All chains should be exported from this file
 */
export { avalancheFuji, sepolia, polygonAmoy } from 'thirdweb/chains';

/**
 * Define the Moonbase Alpha test network
 */
export const moonbase = defineChain({
  id: 1287,
  rpc: 'https://rpc.api.moonbase.moonbeam.network',
});

Deploy ERC-721 NFT Contract

Of course, we'll need to have an NFT contract to showcase as part of the marketplace. You can use an existing NFT contract, but for demo purposes we'll walk through the steps of deploying a new ERC-721 contract with thirdweb.

Head to thirdweb Explore and choose the OpenEditionERC721 NFT standard. You can also access the NFT contract directly. Press Deploy Now, then take the following steps:

  1. Add a name for your NFT
  2. Optionally add a token symbol
  3. Upload the image for your NFT. This will be uploaded to IPFS
  4. Review the royalty information. By default, this is set to the address of your currently connected wallet and the royalty is set by default to 0%
  5. Review the address to receive the proceeds of initial NFT sales. By default, this is set to the address of your currently connected wallet
  6. Select your Network as Moonbase Alpha
  7. Press Deploy Now

Configure ERC-721

You'll be asked for three wallet confirmations - the first two are transactions and the third is a signature. The first transaction deploys the NFT contract and the second sets the NFT metadata. The signature request is simply to add the NFT contract to your dashboard on thirdweb - this is highly recommended as it makes it easy to find your previously deployed NFTs from one easily-accessible place.

Set Claim Condition

Before any NFTs can be minted, you'll need to configure the claim condition. If you try to mint any NFTs before setting the claim condition, the transaction will be reverted. To configure the claim condition for an open public mint, follow these steps:

  1. Head to the Claim Conditions page
  2. Select Public phase
  3. Optionally, choose a price to charge per mint. You can also leave this as 0 for a free mint
  4. Press Save Phases

Set claim conditions

Mint Some NFTs

For aesthetic purposes, we'd like to have some NFTs show up in the marketplace that we created. Under the Extensions, NFTs section, press Claim. Then, you can mint some NFTs by taking the following steps:

  1. Enter the address to receive the NFTs
  2. Enter the desired quantity to mint
  3. Press Claim NFT and confirm the transaction in your wallet

Mint some NFTs

Add NFT Contract to the DApp

After deploying and minting your NFTs, you'll need to specify your NFT contract in src/consts/nft_contract.ts. First, add moonbase to the list of imports as follows:

nft_contracts.ts
import { moonbase, avalancheFuji, polygonAmoy, sepolia } from './chains';

Then, add your NFT contract to the array of marketplace contracts as follows:

nft_contracts.ts
  {
    address: '0x5647fb3dB4e47f25659F74b4e96902812f5bE9Fb',
    chain: moonbase,
    title: 'Moonbase NFT',
    thumbnailUrl:
      'https://258c828e8cc853bf5e0efd001055fb39.ipfscdn.io/ipfs/QmTDyLBf2LaG6mzPniPjpX3P4DTFvjAk3gtUgrAb8EVPUF/2024-05-22%2008.17.59.jpg',
    type: 'ERC721',
  },

To get the IPFS URL of the image of your NFT that you uploaded when creating the NFT contract, head to the Events tab of your NFT contract and locate the SharedMetadataUpdated event. Expand the dropdown and you'll see the image URI. You can concatenate this to an IPFS CDN as shown above.

Get IPFS URL

The finished file can be viewed below:

View nft-contracts.ts
import type { Chain } from 'thirdweb';
import { moonbase, avalancheFuji, polygonAmoy } from './chains';

export type NftContract = {
  address: string;
  chain: Chain;
  type: 'ERC1155' | 'ERC721';

  title?: string;
  description?: string;
  thumbnailUrl?: string;
  slug?: string;
};

/**
 * Below is a list of all NFT contracts supported by your marketplace(s).
 * This is of course hard-coded for demo purposes
 *
 * In reality, the list should be dynamically fetched from your own data source
 */
export const NFT_CONTRACTS: NftContract[] = [
  {
    address: '0x6b869a0cF84147f05a447636c42b8E53De65714E',
    chain: avalancheFuji,
    title: 'Steakhouse: Liberatorz',
    thumbnailUrl:
      'https://258c828e8cc853bf5e0efd001055fb39.ipfscdn.io/ipfs/bafybeigonh3hde5suwcb3qvkh6ljtvxv7ubfmcqbwfvi3ihoi3igd27jwe/SteakhouseLogo.svg',
    type: 'ERC721',
  },
  {
    address: '0xC5A2c72c581eA4A17e17bEeF38a9597132830401',
    chain: avalancheFuji,
    title: 'Ugly Waifu',
    thumbnailUrl:
      'https://258c828e8cc853bf5e0efd001055fb39.ipfscdn.io/ipfs/bafybeidaadqapi7twzd7pjp24tu4ngsr3teubrhop7hg3jk3oj6lqysfgm/OS-LOGO.png',
    slug: 'ugly-waifu',
    type: 'ERC721',
  },

  {
    address: '0x0896Db00D8987Fba2152aa7c14c4255eBC7354cE',
    chain: avalancheFuji,
    title: 'Unnamed Collection',
    description: '',
    thumbnailUrl:
      'https://258c828e8cc853bf5e0efd001055fb39.ipfscdn.io/ipfs/Qmct2vS78Uwug3zVtqQognskPPRmd4wRQiaDAQWt1kRJws/0.png',
    slug: 'unnamed-collection',
    type: 'ERC721',
  },
  {
    address: '0x0ACaCa3d3F64bb6e6D3564BBc891c58Bd4A4c83c',
    chain: avalancheFuji,
    title: 'GoroBot',
    thumbnailUrl:
      'https://258c828e8cc853bf5e0efd001055fb39.ipfscdn.io/ipfs/bafybeiay3ffxy3os56bvnu5cmq7gids4v6n4hf5nvvcb3gy2dzavi3ltnu/profile.jpg',
    slug: 'gorobot',
    type: 'ERC721',
  },
  {
    address: '0x4b6CDEFF5885A57678261bb95250aC43aD490752',
    chain: polygonAmoy,
    title: 'Mata NFT',
    thumbnailUrl:
      'https://258c828e8cc853bf5e0efd001055fb39.ipfscdn.io/ipfs/bafybeidec7x6bptqmrxgptaedd7wfwxbsccqfogzwfsd4a7duxn4sdmnxy/0.png',
    type: 'ERC721',
  },
  {
    address: '0xd5e815241882676F772A624E3892b27Ff3a449c4',
    chain: avalancheFuji,
    title: 'Cats (ERC1155)',
    thumbnailUrl:
      'https://258c828e8cc853bf5e0efd001055fb39.ipfscdn.io/ipfs/bafybeif2nz6wbwuryijk2c4ayypocibexdeirlvmciqjyvlzz46mzoirtm/0.png',
    type: 'ERC1155',
  },
  {
    address: '0x5647fb3dB4e47f25659F74b4e96902812f5bE9Fb',
    chain: moonbase,
    title: 'Moonbase NFT',
    thumbnailUrl:
      'https://258c828e8cc853bf5e0efd001055fb39.ipfscdn.io/ipfs/QmTDyLBf2LaG6mzPniPjpX3P4DTFvjAk3gtUgrAb8EVPUF/2024-05-22%2008.17.59.jpg',
    type: 'ERC721',
  },
];

Deploy Marketplace Contract

While the template includes existing marketplace contracts for a couple of TestNets, let's deploy a similar one for Moonbase Alpha. Head to thirdweb Explore and choose the MarketplaceV3 contract. You can also access MarketplaceV3 directly. Press Deploy Now, then take the following steps:

  1. Add a name for the marketplace
  2. Select Moonbase Alpha as the network
  3. Press Deploy Now

You'll be asked to confirm a transaction and provide a signature. The former deploys the marketplace contract and the latter adds the contract to your dashboard on thirdweb (which is not required but highly recommend for keeping track of your contracts).

Deploy marketplace contract

Add Marketplace Contract to the DApp

After deploying your marketplace contract you'll need to specify it in src/consts/marketplace_contract.ts. To add support for the Moonbase marketplace first add moonbase to the list of imports as follows:

marketplace_contract.ts
import { moonbase, avalancheFuji, polygonAmoy, sepolia } from './chains';

Then, add your marketplace contract in the array of marketplace contracts as follows:

marketplace_contract.ts
  {
    address: '0xA76C6E534aa651756Af8c222686fC1D3abF6952A',
    chain: moonbase,
  },

The finished file can be viewed below:

View marketplace-contracts.ts
import type { Chain } from 'thirdweb';
import { moonbase, avalancheFuji, polygonAmoy, sepolia } from './chains';

type MarketplaceContract = {
  address: string;
  chain: Chain;
};

/**
 * You need a marketplace contract on each of the chains you want to support.
 * Only list one marketplace contract address for each chain
 */
export const MARKETPLACE_CONTRACTS: MarketplaceContract[] = [
  {
    address: '0x8C1D464B385A2B7EAa80dcAAD66DD8BC0256e717',
    chain: avalancheFuji,
  },
  {
    address: '0x571B773F1e4A7C080b51C36f37e06f371C515569',
    chain: polygonAmoy,
  },
  {
    address: '0xe0eFD6fb388405b67b3E9FaFc02649c70E749f03',
    chain: sepolia,
  },
  {
    address: '0xA76C6E534aa651756Af8c222686fC1D3abF6952A',
    chain: moonbase,
  },
];

Wrapping Up

And that's it! Congratulations on making it through the tutorial. You can head to http://localhost:3000 after running the DApp locally via one of the following:

npm run dev
yarn dev
pnpm dev

On the homepage you should see your newly added NFT contract. Click on the NFT collection and you'll see something that looks like the below:

View finished product

For more information on what you can do with thirdweb on Moonbeam be sure to check out the thirdweb guide in the Builders section or the thirdweb documentation site.

This tutorial is for educational purposes only. As such, any contracts or code created in this tutorial should not be used in production.
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
Last update: August 13, 2024
| Created: July 16, 2024