Non-fungible tokens (NFTs) have taken the crypto world by storm throughout most of the past year. With significant celebrity endorsements, mainstream adoption, and growing utility, a host of innovative NFT dApp ideas are driving the adoption of blockchain across all demographics. So, if you’re looking for inspiration for your own NFT app ideas, you’re in the right place!

In this article, we’re going to show you three NFT app ideas that you can create quickly and easily. Furthermore, we’ll explore some of the next-generation tools that you can use to turn your NFT app ideas into exciting games and NFT marketplaces!

Also, if you want to learn the basics of coding, or if you just want to brush up on your JavaScript skills to get the most out of your NFT app ideas, check out the JavaScript Programming for Blockchain Developers course at Moralis Academy!

NFT App Ideas – How to Create NFTs

So, for our first NFT app idea, we will show you how to mint NFTs using Moralis. Furthermore, we’ll show you just how simple it is to mint NFTs in just a few minutes using the Moralis “Rarible NFT Tools” plugin!

Initial Setup to Mint NFTs

To begin, and if you haven’t already, you’ll need to create a free Moralis account. Once you have logged in to your Moralis account, create a server by clicking on the “+ Create a new Server” button at the top-right of the Moralis admin page and then select your server. Next, give your server a name and select the region, network, and chain(s) that you wish to use before clicking on “Add Instance”:

NFT dApp Ideas 3

Next, you’ll need to get the server URL and application ID information that you’ll use inside your “.html” or “.js” files. To obtain this information, click on the “View Details” button next to your server name, as shown in the image below:

Furthermore, we use the server URL and application ID to populate the “.html” or “.js” file to initialize Moralis, as in the example below. Bear in mind that the server details below refer to a specific server. Accordingly, you should input the details of your own server:

Moralis.initialize("W9CCwwg1nQQ1KFrqWYx8YY1nojrxTINwhMHLwYHD"); // Application id for moralis.io
Moralis.serverURL = "https://0iooker5q9ww.usemoralis.com:2053/server"; //Server url from moralis.io

Add the Rarible NFT Tools Plugin

So, now that you have your Moralis server up and running, it’s time to install the “Rarible NFT Tools” plugin. Begin this process by clicking on the arrow button on the right-hand side of your server. Next, click on the “Plugins” button and navigate to the plugin store. In the plugin store, click on the “Read More” button for the plugin in question, and you should see the “Rarible NFT Tools” plugin. After this, simply navigate to the top-right of the page and click on “Install”.

Furthermore, you’ll need to select the appropriate server and configure Rarible. We’ll do this by adding Moralis Speedy Nodes for the Ethereum mainnet and the Rinkeby testnet. You can find these by navigating to the “Speedy Nodes” tab in the Moralis admin panel.

After adding Moralis Speedy Nodes, click on “Install” at the bottom right of the window. It should take a few moments for the plugin to install, so please be patient.

Create an HTML File

Now that your server is operational and the Rarible plugin is installed, you’ll need to structure the content of your dApp using HTML. To begin, you’ll need to open the appropriate code editor and create a new “index.html” file.

You can structure your dApp’s content in a way that suits your own preferences. Moreover, the design and user interface (UI) should meet the requirements of your dApp. However, below is an example of how an NFT minting dApp might look like:

The image above shows that our dApp has a title, three input fields, and a “SUBMIT” button. Accordingly, we need to implement HTML code for each of these elements. You can find the complete HTML code template for this at the Moralis GitHub repository under “index.html”. However, feel free to customize the structure to meet your needs.

Add the dApp’s Logic

Finally, we’re going to add the logic we need to enable users to mint NFTs. Before we begin this final step, we need to initialize Moralis. We can do this by navigating to the “Servers” tab on the Moralis admin panel and clicking on “View Details” for the relevant server. Then, copy the server URL and application ID and input the information at the head of the JavaScript file for the logic of our dApp:

const serverUrl = “INSERT SERVER_URL”;
const appId = “INSERT APP_ID”;

The log for our application is stored in three functions. First, the “login()” function takes care of user authentication via MetaMask. Second, the “initApp()” function renders the interface of our dApp and adds an on-click event to the “SUBMIT” button in our HTML code. All of this can be achieved with just a few lines of code. For an in-depth explanation of how to add these functions, make sure to watch the first video below. Plus, you’ll learn how to implement a simple UI by following the steps in that video.

The “submit()” Function

The “submit()” function holds most of our dApp’s logic. Furthermore, the “submit()” function contains multiple elements. In the first element, we can fetch image data from user uploads to create a Moralis object:

async function submit(){
    const input = document.querySelector('#input_image');
    let data = input.files[0]
    const imageFile = new Moralis.File(data.name, data)
    await imageFile.saveIPFS();
    let imageHash = imageFile.hash();

Now that we have the object, we call the Moralis “saveIPFS()” function. This function enables us to save files using IPFS, with only one line of code. After uploading to IPFS, we fetch the image hash and save it as a variable:

let metadata = {
        name: document.querySelector('#input_name').value,
        description: document.querySelector('#input_description').value,
        image: "/ipfs/" + imageHash
    }
    console.log(metadata);
    const jsonFile = new Moralis.File("metadata.json", {base64 : btoa(JSON.stringify(metadata))});
    await jsonFile.saveIPFS();

The code above shows the construction of a new metadata object that uses the inputted name and description by a user with an image hash. Also, this function stringifies our object to JSON format before reuploading it to IPFS:

let metadataHash = jsonFile.hash();
    console.log(jsonFile.ipfs())
    let res = await Moralis.Plugins.rarible.lazyMint({
        chain: 'rinkeby',
        userAddress: user.get('ethAddress'),
        tokenType: 'ERC721',
        tokenUri: 'ipfs://' + metadataHash,
        royaltiesAmount: 5, // 0.05% royalty. Optional
    })

Following the upload of our object to IPFS, the function proceeds to call the “Moralis.Plugins.rarible.lazyMint()” function. Using just one line of code, we can mint NFTs without paying the initial gas prices. Also, when we call this function, we include network, user address, royalty amount, token type, and token URI information. Now, if this function operates as it should, a success message should appear containing a link that takes users to their newly created NFT:

console.log(res);
    document.querySelector('#success_message').innerHTML = 
        `NFT minted. <a href="https://rinkeby.rarible.com/token/${res.data.result.tokenAddress}:${res.data.result.tokenId}">View NFT`;
    document.querySelector('#success_message').style.display = "block";
    setTimeout(() => {
        document.querySelector('#success_message').style.display = "none";
    }, 5000)
}

That’s it! Minting an NFT has never been so simple. Furthermore, Moralis lowers the entry barrier for creating NFTs that have fewer limitations than most NFT marketplaces. Additionally, Moralis significantly reduces development time, helping you get your NFT app ideas to market quickly and efficiently. Also, in case you missed anything, see our step-by-step video guides below:

NFT App Ideas – How to Create an NFT Marketplace

For our second NFT app idea, we’re going to create an NFT marketplace. For this example, we’ll build a simple example project using Moralis’ SDK. Specifically, we’ll be using Moralis’ ultimate NFT API to streamline the entire process. Also, you can find the complete code for our NFT marketplace on GitHub. The image below shows how our NFT marketplace will look like:

Also, we can see from this image that our NFT marketplace will contain various features, including the user’s native token balance, an “On Sale” section, a “Buy/Sell” section, and the “Your NFTs” section. However, you may also notice that there are currently no NFTs in either the “On Sale” section or the “Buy/Sell” section.

Listing an NFT

When we select an NFT, it becomes available in the “Buy/Sell” section. Also, we can enter a price for our NFT and put it up for sale by clicking on the “Offer for Sale” button. After this, we approve the transaction by clicking on “Confirm” in MetaMask. Then, the window below should appear, showing that an NFT is up for sale in the “On Sale” section:

Buying an NFT

So, now that we have an NFT up for sale, we need to log in using a different account to purchase the NFT. Accordingly, the image below shows how an account can purchase an NFT. First, we click on the “Select” button next to the NFT in the “On Sale” section. Second, we click on the “Buy” button on the NFT in the “Buy/Sell” section and confirm the transaction in MetaMask:

Blog NFT App Ideas 3

Once the NFT has been purchased, it will move from the “On Sale” section to the “Your NFTs” section of the second account we used. Furthermore, once the transaction is complete, the NFT can be sold again.

NFT App Ideas – Create an NFT Marketplace

Now that we know what our NFT marketplace will look like, let’s dive right in and get building! To begin, we’ll take a look at the backend components and features that will enable the functionalities mentioned above.

First, our NFT marketplace will need user authentication to enable signing in and out. Also, we’re going to need to track user balances in real-time. Furthermore, we’ll need the ability to track smart contract events within our dApp. To do this from scratch would take us a long time. However, because we’re using Moralis, this should only take us a few minutes! Moreover, we can simply copy and paste short snippets of code to implement these backend functionalities.

NFT App Ideas – Create a Server

If you haven’t already, you’ll need to set up a free Moralis account so that you can create a Moralis server. Following this, you’ll gain access to a host of valuable tools. Specifically, you’ll be able to create sync events.

In this example, we’re going to create two “listeners” that will detect the events of specific smart contract events. Moreover, as shown in the image below, the first listener will detect each new offer placed within our marketplace, whereas the second will detect the closing of an offer when someone buys an NFT:

Furthermore, in the following image, we can see the Moralis dashboard. Here, you can find a comprehensive database with real-time data about users of the NFT marketplace, with data points including token balances, transaction history, pending transactions, and more. Also, as is outlined in green below, we can access our listener data:

Moreover, the Moralis dashboard provides us with a wealth of on-chain data in one simple-to-navigate interface. Using this data, we can create an NFT marketplace with just a few snippets of code!

Code Overview

Our dApp must function as an authorized contract operator of the NFT marketplace. Also, we need to use a smart contract to ensure that all transactions are executed correctly. By looking at the events below, we can begin to understand the core functionalities of our smart contract:

contract MarketPlace{
event OfferingPlaced(bytes32 indexed offeringId, address indexed hostContract, address indexed offerer,  uint tokenId, uint price, string uri);
event OfferingClosed(bytes32 indexed offeringId, address indexed buyer);
event BalanceWithdrawn (address indexed beneficiary, uint amount);
event OperatorChanged (address previousOperator, address newOperator);

Also, the remaining code from our smart contract defines specific functions to ensure that users can only sell NFTs that they own and that only listed NFTs can be purchased. Furthermore, this code is responsible for allocating a price to the correct token.

Building the dApp

Finally, it’s time to piece our dApp together! We’ve created three files for this example project: “logic.js”, “cloudCode.js”, and “index.html”. You can find the entire code for these files on our GitHub. Furthermore, most of the functionality of our dApp comes from the “logic.js” file, so we’ll be paying extra attention to this. We begin by initializing Moralis by pasting in our Moralis server URL and application ID in our “.js” file:

Moralis.initialize(""); // Application ID from moralis.io
Moralis.serverURL = ""; // Server URL from moralis.io

Next, the code below ensures that all functions are executed correctly when authenticating users: 

Moralis.authenticate().then(function(){
populateNFTs();
populateOfferings();
populateBalance();
subscribeOfferings();
subscribeBuys();
subscribeUpdateNFTs();
});

Also, the rest of our code ensures that we can obtain the correct data using the “populate” and “subscribe” functions and that our users are greeted with a neatly organized display. This is where Moralis saves you time by taking care of the time-consuming backend programming. Moreover, we simply paste in the following snippets of code from our “moralisDashboard” database:

Moralis.Query(“PlacedOfferings”)
Moralis.Query(“ClosedOfferings”)
Moralis.Query(“PolygonNFTOwners”)
Moralis.Cloud.run(“getBalance”, params)
Moralis.Units.FromWei(presentBalance)
Moralis.Cloud.run(“placeOffering”, params)
Moralis.Units.ETH(offering.price)

Security

Additionally, one of the most significant snippets of code in the above is the “Moralis.Cloud.run(“placeOffering”, params)” snippet. This is because it protects the private key of our dApp. Finally, we add the private key of your Ethereum wallet address into the “cloudCode.js” file. 

So, that’s it! Using just a few lines of code and the correct tools, we can create a fully functioning NFT marketplace in minutes! See the video below for an in-depth guide covering this process. Also, you can skip to 6:35 to get right into the code walkthrough:

Furthermore, if you want more inspiration for NFT dApp ideas, check out the Ethereum dApp Programming course at Moralis Academy to learn how to build your own CryptoKitties NFT marketplace clone! Also, see our Unity Blockchain Game Development course if you want to learn the world’s largest game programming framework!

NFT App Ideas – How to Build an NFT Game

Have you ever wondered how to build an NFT game? Well, for the final example in our NFT dApp ideas article, we’re going to do just that! Using around 100 lines of code, we’re going to build a fully functioning NFT game. Also, in this game, avatars will be represented by tokens that can navigate throughout a two-dimensional environment. Furthermore, we’ll be using Aavegotchi NFTs in this example. However, the same logic can also be applied to other NFTs and games.

But, before we dive into building our NFT game, let’s take a look at some of the security features of the game. Because NFT games can offer rewards and prizes, fair play is paramount, and cheating must be eliminated. Accordingly, the majority of the game’s logic will be in our backend code. As such, the primary task of the frontend is asking the server if moving an avatar in a particular direction is valid. 

Moreover, by doing this, we can ensure that users cannot hack the game or cheat against other players. To achieve this, we’ll be using some of Moralis’ high-quality Web3 development tools. Not only does this shorten the entire development process, but it also enables us to focus more time and energy on the user experience.

NFT App Ideas – Setting Up Moralis

Before we jump into writing the code for our NFT game, we need to import the Moralis SDK (software development kit). Also, we need to create a server and initialize Moralis. First, to set up our server, we need to log in to Moralis. After logging in, simply click on the “+ Create a new Server” button. Then, a drop-down menu should appear with three options. At this point, we can select any of the server options available. However, for this example, we recommend selecting the testnet option.

So, now that we’ve selected our server, we need to give our server a name and select region and network(s). After selecting this, we click on “Add Instance” to spin up the server. This could take a few minutes, so hold tight! Once the server is running, we need to import the Moralis SDK so that we can access valuable libraries and tools when programming. Furthermore, importing the Moralis SDK requires just a couple of lines of code:

<script src="https://cdn.jsdelivr.net/npm/web3@latest/dist/web3.min.js"></script>
<script src="https://npmcdn.com/moralis@latest/dist/moralis.js"></script>

Finally, we need to initialize Moralis using the server URL and application ID of our selected server. To find this information, click on the “View Details” button on the relevant server. Once the URL and ID have been inputted, your code should look something like this:

<script>
  Moralis.initialize("NslpKz5UCV2yfRwP9TtIK62AWozVdge5XjGDeRR");
  Moralis.serverURL = "https://mg5go64nsivf.usemoralis.com:2053/server";

Authenticating Users

When interacting with our NFT game, players need to be able to log in and authenticate themselves. We’ll be using MetaMask for authentication, which we can achieve with one line of code:


var user = await Moralis.Web3.authenticate();

Note: The above is part of the “login()” function. For a more in-depth explanation, please watch the video further down.

Now, when a user logs in, they will be added to your Moralis database. Furthermore, to view all of the users in your server’s database, click on the three dots on the relevant server and click on “Dashboard”. On the left-hand side of the dashboard, navigate to the “Browser” tab. There are several useful functions under this tab. However, for this example, we’re going to focus on the “EthNFTOwners” page. This allows us to see all of the NFTs our users hold along with their crypto addresses using just a single line of code.

Graphics

Next up, we need to develop some graphics for our NFT game. For the purpose of this demonstration, we’ll be using an open-source HTML5 game library called “Phaser”. Furthermore, Phaser makes it incredibly straightforward to create simple graphics like the ones we’ll be using in this game. Accordingly, we’ll need to initialize the Phaser library. As such, your code should look something like this:

var config = {
      type: Phaser.AUTO,
      width: 1200,
      height: 700,
      scene: {
        preload: preload,
        create: create,
        update: update
      },
      physics: {
        default: 'arcade',
        arcade: { debug: true }
      }
    };

Game Lifecycle

Next, our game needs a lifecycle. For this, we begin by using a “preload” function to load our background. The code below shows that only the background of our game is preloaded:

function preload ()
    {
      ping();
      context = this;
      context.load.image('background', 'bg.jpg');
    }

Furthermore, there are some avatars that we want to load. However, we cannot preload these as they belong to players. Since we don’t know which players will be playing until they log in, we can’t know which avatars to load onto the screen. Therefore, we need to fetch this data from the blockchain.

Also, you may have noticed the “ping()” function in the code. We execute this function to continuously ping the server so that the server understands which players are playing the game at any given time. You can see how this function appears in the code below:

async function ping(){
      setTimeout(ping,1000)
      await Moralis.Cloud.run(''ping'');
    }

Controls and Subscription

Ok, now that we have the function for the graphics in place, we need to add some controls. Plus, we need to implement a subscription to the “GameState” via the “GameState” tab in the database of our Moralis server. The GameState informs us of the location of each player. Moreover, whenever something changes in the GameState, the subscription updates every client. As a result, we get an alert whenever another player moves:

async function create ()
    {
      this.wKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.W);
      this.aKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.A);
      this.sKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.S);
      this.dKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.D);

      // wait for game state update
      let query = new Moralis.Query("GameState");
      let subscription = await query.subscribe();
      query.equalTo("stateType", "globalGameState");
      subscription.on('update', (object) => {
        state = object.get("state");
        console.log(state)
      });

Because we’re using Moralis, most of the leg work is done for us in terms of nuanced WebSocket infrastructures and logic. Furthermore, to ensure that our NFT game knows the state of each player and their position on the map, all we need is the above subscription code.

Update Function

Now that we’ve outlined the controls of our game and created a subscription to the GameState, we also need to implement an update function. Furthermore, the purpose of this function is to listen to the keys that are pressed before sending a request to the server to change the position of an in-game character. Below is an example of what part of the code should look like for moving an avatar upwards:

async function  update ()
    {
      cursors = this.input.keyboard.createCursorKeys();
      const params =  { cursors: cursors };

      if (this.wKey.isDown) {

        if(!buttonsLocked["up"]){
          console.log('W is pressed');

          buttonsLocked["up"]=true;
          await Moralis.Cloud.run("move", {direction:"up"});
          buttonsLocked["up"]=false;
        }

}

Also, it’s worth bearing in mind that we won’t be moving the character in our game right away. Instead, we’re simply sending a request to the server to do this. Furthermore, the server determines if it is possible to move a character or not. Accordingly, the server prevents users from cheating by inhibiting the illegal movement of players. Moreover, only by playing the game can a character be moved.

function drawState(){

      for (let userId in state) {

        // new player that we haven't seen - need to load image, create sprite
        if(!sprites[userId]){

          sprites[userId] = {loading:true}

          const svgBlob = new Blob([state[userId].svg], {type:"image/svg+xml;charset=utf-8"})
          const url = URL.createObjectURL(svgBlob)

          context.load.image('player'+userId,url).on('filecomplete', function(){
            if(sprites[userId].loading)
            {
              sprites[userId].loading = false
              setTimeout(function(){ //had to add this delay for images to always show
                sprites[userId] =  context.physics.add.image(state[userId].x, state[userId].y, 'player'+userId).setScale(0.5,0.5).setOrigin(0,0);
              },1000)
            }
          }, context);
          context.load.start()
        }

Drawing the State

Our final function will draw the state of our NFT game. If a player is not known, our “drawState” function will fetch the player’s SVG (two-dimensional vector graphic) from the blockchain via the Moralis server. We will discuss SVGs in more detail as we progress to the backend of our NFT game. However, if our player isn’t new, the game will move the relevant avatar around the gaming environment. Below is an example of what the code for this should look like:

else{

          if(sprites[userId].x<state[userId].x)
            sprites[userId].x+=5;

          else if(sprites[userId].x>state[userId].x)
              sprites[userId].x-=5;



          if(sprites[userId].y<state[userId].y)
              sprites[userId].y+=5;

          else if(sprites[userId].y>state[userId].y)
              sprites[userId].y-=5;

We only need a few functions for a player to move around our 2D environment. Additionally, for our clients to have real-time updates regarding every player of the game, our code must subscribe to the GameState. Moreover, we achieve this by using just a few lines of code. As such, our frontend is taken care of. Now it’s time to take a look at the backend.

Blog NFT App Ideas 2

The “updateState” Function

Furthermore, our backend will contain more of the functions and logic that our frontend calls during gameplay. As you can see, we saved a great deal of time developing the frontend using Moralis. However, our backend development process is even more straightforward!

Below is the function we use for moving the avatars within the game. Also, whenever a player presses a key to move their avatar, the move function receives the direction of the avatar’s movement before updating the state of the game. In the example below, we can see that the move function also calls the “updateState” function. The “updateState” function is responsible for moving the avatar. In this example, the “updateState” function is moving the avatar by five units in the chosen direction of the player:

Moralis.Cloud.define("move", async (request) => {
  logger.info("Move called!");
  logger.info(JSON.stringify(request));

  const userId = request.user.get("username");

  // create and write to DB new version of the state
  const direction = request.params.direction;
  updateState(userId,direction);
  await persistState();
});

Also, you may notice a comment in the above code explaining that we can include additional logic. Accordingly, we’re able to add in-game items that an avatar can collect. Plus, we can include boundaries and obstacles to limit the movement of avatars. Moreover, our server can recognize any obstacles and may restrict movement as required.

function updateState(userId,direction){

  logger.info("updateState ", userId, "direction ", direction);

  // TODO - add server-side logic to restrict movements, add pickup items, etc

  if(direction == "up"){
    state[userId].y-=5;
  }
  else if(direction == "down"){
    state[userId].y+=5;
  }
  else if(direction == "left"){
    state[userId].x-=5;
  }
  else if(direction == "right"){
    state[userId].x+=5;
  }


}

The “persistState” Function

Next, we want to implement the “persistState” function. This function enables the GameState to be saved to the database of our Moralis server. As such, below is an example of what this function should look like:

async function persistState(){



  var gameState = await stateDBReference();

  // upload the state
  gameState.set("state",state)
  await gameState.save(null,{useMasterKey:true})
}

After the state is saved, each client is updated with the new GameState. This enables real-time communication between the server and the clients. Plus, we can achieve this using under ten lines of code thanks to the subscription function operating in our frontend. 

Furthermore, we’ll use a ping function for checking when a user pings the server. When this happens, it is saved to the state of the game:

Moralis.Cloud.define("ping", async (request) => {

  // either add the user to current game state, or update last ping
  const userId = request.user.get("username");
  const ethAddress = request.user.get("authData").moralisEth.id;

  if(!state[userId])
  {
    state[userId] = {x:0,y:0,lastPing:Date.now(), displayAddress: ethAddress}
  }
  else{
    state[userId].lastPing = Date.now()
  }

The “getSVGString” Function

Additionally, this function helps us to fetch the SVG from the blockchain. To do this, we must query each user for their NFTs. Then, once we have this information, we’re able to fetch SVGs from the blockchain using another function called “getSVGString”. 

else{
    state[userId].lastPing = Date.now()
  }

  if(!state[userId].svg){
    //get aavegochi owned
    const EthNFTOwners = Moralis.Object.extend("EthNFTOwners");
    const query = new Moralis.Query(EthNFTOwners);
    query.equalTo("owner_of", ethAddress);
    query.equalTo("token_address", "0x07543db60f19b9b48a69a7435b5648b46d4bb58e");
    const results = await query.find();
    if(results.length>0){
      const token_id = results[0].get("token_id")
      const svg = await getSVGString(token_id);
      state[userId].svg = svg;
    }
  }

  persistState();

});

Also, the code in the image below shows that the ping function calls the “getSVGString” function. Although this may look daunting due to the amount of code, we can simply copy and paste the ABI from the Aavegotchi contract.

Blog NFT dApp Ideas

So, there you have it! That’s how simple it is to create an NFT game! Plus, because we’re using Moralis, we save hours of development time. Moreover, with the proper tools, we can create an exciting NFT game in record time! Also, see the video below if you want a visual walkthrough of this process:

NFT App Ideas – Summary

NFTs are undoubtedly one of the most popular trends in crypto and a driving force in the 2021 bull run. Furthermore, the Moralis tool suite makes it easier than ever to bring your NFT app ideas to life with our time-saving code snippets.

Blog NFT App Ideas

Moralis Academy is the ultimate Web3 and blockchain education platform online. Check out our Ethereum Smart Contract Programming 101 course to gain a firm understanding of Solidity and smart contracts. Furthermore, see our Ethereum Game Programming course if you want to pursue a career in blockchain gaming. Regardless of experience, Moralis Academy has the perfect courses to help you become blockchain certified! Join our community of over 30,000 students today at Moralis Academy! Also, don’t forget to follow us on Twitter @MoralisAcademy! We’d love to hear about your NFT app ideas!