EVM NFT Creation

A developers guide to creating NFTs on EVM blockchains which are compatible with GhostMarket


This page provides a step-by-step guide for deploying GhostMarket compatible NFTs on supported EVM compatible blockchains (Avalanche, BSC, Polygon, Ethereum, Base).

The NFT creation process requires interaction with the blockchain. For retrieving existing NFT metadata, see Accessing NFT data, which uses the GhostMarket APIs.

The snippets used in this guide are javascript and the contract addresses used are for the BSC contracts. For other EVM chains, please adjust using the appropriate contract addresses specified in the Contracts page.

The code snippets also assume a node.js environment.

See our Metadata Reference for full details and requirements of GhostMarket NFT metadata.

NFT Creation

The NFT creation process on all blockchains broadly consists of the following steps.

  1. Prepare Off-Chain Media and persist it

  2. Assemble On/Off-Chain Metadata

  3. Persist Off-Chain metadata

  4. Build a transaction

  5. Sign the transaction

  6. Broadcast to the blockchain

1. Prepare your Off-Chain Media

The preferred decentralized platform for persisting image/media data for your NFT is IPFS.

This guide will use Piñata to upload and pin your images to IPFS.

Set up a Piñata account and get started here.

You can either manually upload you metadata, noting the IPFS hash, or dive into the Pinata js-sdk to interact with Piñata programatically.

Be sure to note the IPFS hash of the uploaded metadata, you will need it in the following step.

Prepare the Web3 javascript environment

Install the web3 javascript module

% npm install web3

Import the Web3 module and set up Web3

This sample assumes node.js, for browser and metamask development, adapt the provider and wallet connection appropriately.

const Web3 = require("web3");

// connect the sample provider - set your own provider appropriately
const web3 = new Web3(Web3.givenProvider || "ws://localhost:8545");

// Create a sample PK & account
const privateKey =
account = web3.eth.accounts.privateKeyToAccount(privateKey);

// "ghost" NFT contracts for mainnet BSC
const erc721ContractAdd = "0xf41db445d7eaf45536985ce185ce131fa4b42e68";
const erc1155ContractAdd = "0x44c5ce28c29934b71a2a0447745d551dfc7b5133";

Download and save the contact ABI using the relevant explorer (e.g. BSC ERC721) and store it locally. Node.js allows us to "require" it directly into the ABI objects.

After downloading the contract ABI, be sure to edit the file so it contains only the value of the "result" object

e.g. [{ "anonymous" true ... }]

const erc721ABI = require("./ERC721Abi.json");
const erc1155ABI = require("./ERC1155Abi.json");

2. Assemble On/Off-Chain Metadata

GhostMarket supports both ERC721 and ERC1155 NFT token standards on EVM platforms. The metadata setup is identical, however the contract parameters differ. We highlight these differences below.

GhostMarket EVM NFT contracts provide the option to store metadata on, or off chain as a JSON string. However, because of the high cost of storing Metadata on-chain, we will be storing the metadata off-chain.

Build the metadata:

const attributes = [
    trait_type: "color", // The attribute type/key
    value: "red", // The attribute value
    display_type: "", // The display format
    trait_type: "size", // The attribute type/key
    value: "small", // The attribute value
    display_type: "", // The display format
  // No third attribute
  // An arbitrary number of attributes may be added for custom apps

const properties = {
  has_locked: true, // Is there locked content?
  type: 1, // Taken from the predefined genres

// Put it together
const jsonMetadata = JSON.stringify({
  name: "My Shiny NFT",
  description: "This NFT will be a classic",
  image: "ipfs://QmTy8w65yBXgyfG2ZBg5TrfB2hPjrDQH3RCQFJGkARStJb", //URI from Media step
  tokenURI: "",

3. Persist metadata to IPFS

Since this example uses Off-chain persistence of the NFT metadata. Upload the metadata to IPFS using the same process as persisting the media and again.

Be sure to note the IPFS hash, we will use this below.

4. Build the transaction

The royalties and lockedContent are parameters to the contract method, so these are prepared first.

This code snippet constructs the contract & method objects for both the ERC721 & ERC1155 contracts. Use the contract which corresponds to your use case.

// construct the royalties ARRAY.
const royaltyBPS = 2000; // royalties - 20% expressed in Basis Points (BPS) (0.01%)

// Royalties is an array of 2 element arrays in [address, percentage] format
const royalties = [
  [account.address, royaltyBPS],
  // Additional royalty address/value pairs may be added here

// The locked content - ToDo - Describe fully
// Node.js only - add module "npm i buffer" for browsers
const lockedContent = Buffer.from("My secret Locked Content", "utf8").toString(

// Create the contract object
const erc721contract = new web3.eth.Contract(erc721ABI, erc721ContractAdd);
const erc1155contract = new web3.eth.Contract(erc1155ABI, erc1155ContractAdd);

const methodData1155 = erc1155contract.methods.mintGhost(

const methodData721 = erc721contract.methods.mintGhost(

5. Sign the Transaction

Not needed here. In this sample, signing is done as part of the Web3 Broadcast.

6. Broadcast the Transaction to the network

// Broadcast the Txn - Identical call for both ERC-721 and ERC1155 contract types
methodData721.send({ from: account.address, value: 0 });

That's it, you've created and persisted a GhostMarket compatible NFT.

For clarity, all of the above snippets exclude error and promise handling for clarity. Production code should include thorough exception management and handle promises appropriately.

Last updated