How to build a Simple Metaverse Contract

Intermediate

 

How to build a Simple Metaverse Contract

This tutorial provides a step-by-step guide on how to create a simple metaverse contract called Polyland on the Harmony blockchain using the HRC-721 token standard (NFT). The contract represents a plot of land that is divided into patches, which can be owned by different accounts. The tutorial uses Chainstack to create a public chain project and join the Harmony devnet, Foundry to create and deploy the contract, and the Harmony explorer to verify the contract and distribute patches to accounts. The tutorial assumes that you have a Chainstack account and have installed Foundry. The tutorial covers creating the project, joining the devnet, accessing node credentials, creating the contract, flattening, compiling, and deploying the contract, verifying the contract on the explorer, and distributing patches to accounts.

A simple metaverse contract with Foundry

This tutorial will guide you through the process of creating a simple metaverse contract on the Harmony blockchain using the HRC-721 token standard, also known as NFT. The contract, called Polyland, represents a plot of land that is divided into patches, which can be owned by different accounts. The tutorial will cover the steps necessary to create the contract, program it to consist of patches of land, deploy it on the Harmony devnet through a node deployed with Chainstack, and distribute patches to different accounts on the Harmony devnet. The goal of this tutorial is to provide you with a basic understanding of how to create and deploy a metaverse contract on the Harmony blockchain using NFTs.

Prerequisites

Overview

To get from zero to a deployed metaverse contract and patches of land distributed on the Harmony devnet, do the following

With Chainstack, create a public chain project.

With Chainstack, join the Harmony devnet.

With Chainstack, access your Harmony node credentials.

With OpenZeppelin, create an HRC-721 contract.

With Foundry, flatten, compile, and deploy the contract through your Harmony node.

Verify the contract on the Harmony explorer.

Using the Harmony explorer as a web app, distribute the patches of land to accounts.

Step-by-step

Create a public chain project

See Create a project.

Join the Harmony devnet

See Join a public network.

Get your Harmony node access and credentials

See View node access and credentials.

Install Foundry

See Foundry (opens new window).

Create the contract

Initialize your project with Foundry:

 

forge init polyland

 

This will create the project directory polyland an initialize it.

Go to the polyland/src/ directory. In the directory, create your metaverse contract: polyland.sol.

 

// SPDX-License-Identifier: MIT
pragma solidity ^0.8;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract Polyland is ERC721, Ownable {
    using Counters for Counters.Counter;
    
    Counters.Counter private supply;

    uint256 public maxSupply = 4;

    struct Triangle {
        string name;
        int8 edge1;
        int8 edge2;
        int8 edge3;
    }

    Triangle[] public triangles;

    constructor() ERC721("Polyland", "PLLND") {
    triangles.push(Triangle("Triangle0", 0,0,0));
    triangles.push(Triangle("Triangle1", 1,1,1));
    triangles.push(Triangle("Triangle2", 2,2,2));
    triangles.push(Triangle("Triangle3", 3,3,3));
    triangles.push(Triangle("Triangle4", 4,4,4));
    }

    modifier supplyCap {
      require(supply.current() <= maxSupply, "All patches minted.");
      _;
    }

    function totalSupply() public view returns (uint256) {
      return supply.current();
    }

    function getTriangles() public view returns (Triangle[] memory) {
      return triangles;
    }

    function mintTriangle(address account)
        public
        onlyOwner
        supplyCap
        returns (uint256)
    {
        supply.increment();

        uint256 newPatchId = supply.current();
        _mint(account, newPatchId);
      
        return newPatchId;
    }
}

 

 

The contract implementation is the following:

  • The contract uses the OpenZeppelin audited ERC-721 contract templates (opens new window).

  • The contract consists of the Triangle object with three edge properties. The triangle is a patch of land that has three edges.

  • The constructor function sets the contract up with four triangles. Since this is an array and starts with 0, while the ID of the minted patch starts with 1, the first element is set to Triangle0. Triangle0 is the default first element that will not represent a patch of land in the Polyland metaverse.

  • Through the maxSupply variable and the supplyCap modifier, the number of patches available to mint is capped at 4.

  • Only the address that deploys the contract can mint the patches of land.

Thus, the contract represents a plot of land called Polyland that consists of four triangular patches of land.

  1. Set up OpenZeppelin with Foundry

Install OpenZeppelin with Foundry:

forge install openzeppelin/openzeppelin-contracts

 

In the project directory, create a remappings.txt file with the following contents:

 
 
@openzeppelin/=lib/openzeppelin-contracts/

 

Flatten the contract

Flatten the contract to make it easier to verify on the Harmony devnet explorer (opens new window).

Run:

forge flatten polyland.sol > polylandFlat.sol

 

Deploy the contract:

 

forge create CONTRACT_NAME --contracts CONTRACT_PATH --private-key PRIVATE_KEY --rpc-url HTTPS_ENDPOINT --legacy

 

where

  • CONTRACT_NAME — the name of the contract as provided in the contract code contract Polyland is ERC721, Ownable.

  • CONTRACT_PATH — full path to the flattened contract.

  • PRIVATE_KEY — the private key to the account that deploys the contract. Must be used without the 0x prefix. Fund the account with devnet ONE using the devnet faucet (opens new window).

  • HTTPS_ENDPOINT — your Harmony node HTTPS endpoint. See also View node access and credentials and Tools.

  • --legacy — the Foundry flag to work with the EVM-based networks that are not EIP-1559 (opens new window)activated.

Example:

forge create Polyland --contracts /root/polyland/src/polylandFlat.sol --private-key 671f1be339521731fef5f0aef7957e1f6653ae27fa58b528242f160a8cfd58dc --rpc-url https://nd-123-456-789.p2pify.com/3c6e0b8a9c15224a8228b9a98ca1531d --legacy

 

 

Once the contract deploys, note the solc and the Deployed to values in the output.

Verify the contract

Open the Harmony devnet explorer (opens new window).

Put in the contract address. Click the Contract tab.

Click Verify and Publish.

In the Contract Name field, put Polyland.

Set Chain Type to devnet.

In Compiler, provide the solc version that the contract compiled with.

In Optimizer, set Yes, 200. Contract bytecode optimization with 200 runs is the default Foundry setting.

Paste the entirety of the flattened contract in the contract field and hit Submit.

This will verify the contract. You can now use the explorer as a web app to interact with the contract.

Distribute the patches of land

On the contract page in the Harmony devnet explorer (opens new window), click Write Contract

In mintTriangle, provide an address to distribute a patch of land to. Distribute the patches to different addresses until you hit the cap with the All patches minted message.

On the Read Contract tab, query the ownerOf field by putting in the tokenId values representing each of the patches of land: 1, 2, 3, 4.

In the triangles field, put in the same tokenId values to get the data on each of the patches: name and the size of each of the three edges.

Conclusion

This tutorial guided you through the basics of creating and deploying a metaverse contract with object ownership representation.

You created your own plot of land, distributed the finite number of land patches to different owners and retrieved the data for each of the patches: patch size and patch owner.

You did all of it using Foundry (opens new window).

This tutorial uses devnet, however the exact same instructions and sequence work on the mainnet.