> ## Documentation Index
> Fetch the complete documentation index at: https://docs.chainstack.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Harmony: A simple metaverse contract with Foundry

> Deploy a Polyland ERC-721 metaverse contract on Harmony devnet using Foundry, minting finite land patches as NFTs through a Chainstack endpoint.

**TLDR:**

* This tutorial showcases how to create an ERC-721 “Polyland” contract on Harmony devnet that treats each land patch as an NFT.
* Polyland can hold a finite set of triangular patches, and the owner (contract deployer) can mint them to different accounts until the supply is capped.
* Foundry is used to compile and deploy the contract, then the Harmony explorer is used to verify it and distribute patches.
* Once deployed, each patch’s owner and properties (triangle edges) can be queried on-chain, illustrating the fundamentals of a metaverse asset contract.

## Main article

The blockchain part of any metaverse that involves decentralization is object ownership.

On Harmony, object ownership can be realized with the HRC-721 token standard, commonly known as NFT.

A very basic example of realizing a metaverse on blockchain is creating a plot of land and distributing the patches of it to different owners—all through an NFT contract.

In this tutorial, you will:

* Create a simple contract called Polyland. The Polyland contract represents a plot of land.
* Program Polyland to consist of patches of land.
* Deploy Polyland on the Harmony devnet through a node deployed with Chainstack.
* Distribute patches of Polyland to different accounts on the Harmony devnet.

## Prerequisites

* [Chainstack account](https://console.chainstack.com/) to deploy a Harmony node.
* [Foundry](https://getfoundry.sh/) to create and deploy contracts.

## Overview

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

1. With Chainstack, create a <Tooltip tip="A public chain project- a project to join public networks">public chain project</Tooltip>.
2. With Chainstack, join the Harmony devnet.
3. With Chainstack, access your Harmony node credentials.
4. With OpenZeppelin, create an HRC-721 contract.
5. With Foundry, flatten, compile, and deploy the contract through your Harmony node.
6. Verify the contract on the Harmony explorer.
7. 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](/docs/manage-your-project#create-a-project).

### Join the Harmony devnet

See [Join a public network](/docs/manage-your-networks).

### Get your Harmony node access and credentials

See [View node access and credentials](/docs/manage-your-node#view-node-access-and-credentials).

### Install Foundry

See [Foundry](https://getfoundry.sh/).

### Create the contract

1. Initialize your project with Foundry:

   ```bash theme={"system"}
   forge init polyland
   ```

   This will create the project directory `polyland` and initialize it.

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

   ```solidity theme={"system"}
   // 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](https://docs.openzeppelin.com/contracts/4.x/erc721).
   * The contract consists of a `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.

3. Set up OpenZeppelin with Foundry

   Install OpenZeppelin with Foundry:

   ```bash theme={"system"}
   forge install openzeppelin/openzeppelin-contracts
   ```

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

   ```
   @openzeppelin/=lib/openzeppelin-contracts/
   ```

4. Flatten the contract.

   Flatten the contract to make it easier to verify on the [Harmony Testnet explorer](https://explorer.testnet.harmony.one).

   Run:

   ```bash theme={"system"}
   forge flatten polyland.sol > polylandFlat.sol
   ```

5. Deploy the contract:

   ```bash theme={"system"}
   forge create Polyland --contracts /root/polyland/src/polylandFlat.sol --private-key YOUR_PRIVATE_KEY --rpc-url YOUR_CHAINSTACK_ENDPOINT --legacy
   ```

   where

   * `Polyland` — the name of the contract as provided in the contract code `contract Polyland is ERC721, Ownable`
   * `/root/polyland/src/polylandFlat.sol` — full path to the flattened contract
   * YOUR\_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 [testnet faucet](https://faucet.pops.one/).
   * YOUR\_CHAINSTACK\_ENDPOINT — your Harmony node HTTPS endpoint deployed with Chainstack. See also [View node access and credentials](/docs/manage-your-node#view-node-access-and-credentials) and [Harmony tooling](/docs/harmony-tooling).
   * `--legacy` — the Foundry flag to work with the EVM-based networks that are not [EIP-1559](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1559.md) activated.

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

### Verify the contract

1. Open the [Harmony Testnet explorer](https://explorer.testnet.harmony.one).
2. Put in the contract address. Click the **Contract** tab.
3. Click **Verify and Publish**.
4. In the `Contract Name` field, put `Polyland`.
5. Set `Chain Type` to `devnet`.
6. In `Compiler`, provide the `solc` version that the contract compiled with.
7. In `Optimizer`, set `Yes`, `200`. Contract bytecode optimization with 200 runs is the default Foundry setting.
8. 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

1. On the contract page in the [Harmony Testnet explorer](https://explorer.testnet.harmony.one), click **Write Contract**.
2. 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.
3. 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`.
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](https://chainstack.com/foundry-a-fast-solidity-contract-development-toolkit/).

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

### About the author

<CardGroup>
  <Card title="Ake">
    <img src="https://mintcdn.com/chainstack/UN3rP7zhB69idvnC/images/docs/profile_images/1719912994363326464/8_Bi4fdM_400x400.jpg?fit=max&auto=format&n=UN3rP7zhB69idvnC&q=85&s=792a24ab1b4682406fa589c0ecd88e5d" alt="Ake" style={{width: '80px', height: '80px', borderRadius: '50%', objectFit: 'cover', display: 'block', margin: '0 auto'}} noZoom width="400" height="400" data-path="images/docs/profile_images/1719912994363326464/8_Bi4fdM_400x400.jpg" />

    <Icon icon="code" iconType="solid" /> Director of Developer Experience @ Chainstack
    <br /><Icon icon="screwdriver-wrench" iconType="solid" /> Talk to me all things Web3
    <br />20 years in technology | 8+ years in Web3 full time years experience

    <div style={{display: "flex", justifyContent: "center", gap: "12px"}}>
      <a href="https://github.com/akegaviar/" style={{textDecoration: "none", borderBottom: "none"}}>
        <Icon icon="github" iconType="brands" />
      </a>

      <a href="https://twitter.com/akegaviar" style={{textDecoration: "none", borderBottom: "none"}}>
        <Icon icon="twitter" iconType="brands" />
      </a>

      <a href="https://www.linkedin.com/in/ake/" style={{textDecoration: "none", borderBottom: "none"}}>
        <Icon icon="linkedin" iconType="brands" />
      </a>
    </div>
  </Card>
</CardGroup>
