This section will guide you through deploying an NFT smart contract (ERC-721) on the Mode Network Testnet using Hardhat.
Hardhat is a developer tool that provides a simple way to deploy, test, and debug smart contracts.
Materials that need to be prepared:
Node v18+
This guide requires you have Node version 18+ installed.
Download Node v18+
Metamask Wallet
In order to deploy a smart contract, you will first need a web3 wallet. You can create a wallet by downloading the Metamask Wallet browser extension.
Download Metamask Wallet
Wallet funds
Deploying contracts to the blockchain requires a gas fee. Therefore, you will need to fund your wallet with ETH to cover those gas fees.
For this guide, you will be deploying a contract to the Mode Network Testnet. You can fund your wallet with Mode Sepoila ETH using the following options:
For more detailed steps on funding your wallet with Mode Sepoila ETH, see Network Faucets.
Creating a project
Before you can begin deploying smart contracts to Mode, you need to set up your development environment by creating a Node.js project.
To create a new Node.js project, run Command Prompt:
npm init --y
To install Hardhat, run Command Prompt:
npm install --save-dev hardhat
To create a new Hardhat project, run Command Prompt:
Select Create a TypeScript project
then press enter to confirm the project root.
Select y
for both adding a .gitignore
and loading the sample project. It will take a moment for the project setup process to complete.
Configuring Hardhat with Mode
In order to deploy smart contracts to the Mode Network, you will need to configure your Hardhat project and add the Mode Network.
To configure Hardhat to use Mode, add Mode as a network to your project’s hardhat.config.ts
file:
import { HardhatUserConfig } from 'hardhat/config';
import '@nomicfoundation/hardhat-toolbox';
require('dotenv').config();
const config: HardhatUserConfig = {
solidity: {
version: "0.8.17",
},
networks: {
// for testnet
"mode-testnet": {
url: "https://sepolia.mode.network",
accounts: [process.env.WALLET_KEY as string],
gasPrice: 1000000000,
},
},
defaultNetwork: "hardhat",
};
export default config;
Install Hardhat toolbox
The above configuration uses the @nomicfoundation/hardhat-toolbox
plugin to bundle all the commonly used packages and Hardhat plugins recommended to start developing with Hardhat.
To install @nomicfoundation/hardhat-toolbox
, run Command Prompt:
npm install --save-dev @nomicfoundation/hardhat-toolbox
Loading environment variables
The above configuration also uses dotenv to load the WALLET_KEY
environment variable from a .env
file to process.env.WALLET_KEY
. You should use a similar method to avoid hardcoding your private keys within your source code.
To install dotenv
, run Command Prompt:
npm install --save-dev dotenv
Once you have dotenv
installed, you can create a .env
file with the following content:
WALLET_KEY=<YOUR_PRIVATE_KEY>
Substituting <YOUR_PRIVATE_KEY>
with the private key for your wallet.
CAUTION
WALLET_KEY
is the private key of the wallet to use when deploying a contract. For instructions on how to get your private key from Metamask Wallet, visit the Metamask Wallet documentation. It is critical that you do NOT commit this to a public repo
Compiling the smart contract
Below is a simple NFT smart contract (ERC-721) written in the Solidity programming language:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
contract NFT is ERC721 {
using Counters for Counters.Counter;
Counters.Counter private currentTokenId;
constructor() ERC721("NFT Name", "NFT") {}
function mint(address recipient)
public
returns (uint256)
{
currentTokenId.increment();
uint256 tokenId = currentTokenId.current();
_safeMint(recipient, tokenId);
return tokenId;
}
}
The Solidity code above defines a smart contract named NFT
. The code uses the ERC721
interface provided by the OpenZeppelin Contracts library to create an NFT smart contract. OpenZeppelin allows developers to leverage battle-tested smart contract implementations that adhere to official ERC standards.
To add the OpenZeppelin Contracts library to your project, run Command Prompt:
npm install --save @openzeppelin/contracts
In your project, delete the contracts/Lock.sol
contract that was generated with the project and add the above code in a new file called contracts/NFT.sol
. (You can also delete the test/Lock.ts
test file, but you should add your own tests ASAP!).
To compile the contract using Hardhat, run Command Prompt:
npx hardhat compile
Deploying the smart contract
Once your contract has been successfully compiled, you can deploy the contract to the Mode Sepoila test network.
To deploy the contract to the Mode Sepoila test network, you’ll need to modify the scripts/deploy.ts
in your project:
import { ethers } from 'hardhat';
async function main() {
const nft = await ethers.deployContract('NFT');
await nft.waitForDeployment();
console.log('NFT Contract Deployed at ' + nft.target);
}
// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
You also need an ETH testnet in your wallet. See the prerequisites above if you haven’t already. Otherwise, the deployment attempt will fail.
Finally, run Command Prompt:
npx hardhat run scripts/deploy.ts --network mode-testnet
The contract will be deployed on the Mode Sepoila test network. You can view the deployment status and contract by using a block explorer and searching for the address returned by your deploy script. If you’ve deployed an exact copy of the NFT contract above, it will already be verified and you’ll be able to read and write to the contract using the web interface.
Regardless of the network you’re deploying to, if you’re deploying a new or modified contract, you’ll need to verify it first.
Verifying the Smart Contract
If you want to interact with your contract on the block explorer, you, or someone, needs to verify it first. The above contract has already been verified, so you should be able to view your version on a block explorer already. For the remainder of this guide, we’ll walk through how to verify your contract on Mode Sepoila testnet.
In hardhat.config.ts
, configure Mode Sepoila as a custom network. Add the following to your HardhatUserConfig
:
Blockscout
// Hardhat expects etherscan here, even if you're using Blockscout.
etherscan: {
apiKey: {
"mode-testnet": process.env.BLOCKSCOUT_KEY as string,
},
customChains: [
{
network: "mode-testnet",
chainId: 919,
urls: {
apiURL: "https://sepolia.explorer.mode.network/api",
browserURL: "https://sepolia.explorer.mode.network",
},
},
],
},
INFO
You can use the Blockscout API key when using the below because you cannot yet register an account on the Blockscout Sepoila Mode Network.
.env
WALLET_KEY=<YOUR_PRIVATE_KEY>
BLOCKSCOUT_KEY=MODE-NETWORK-TESTNET
Now, you can verify your contract. Grab the deployed address and run Command Prompt:
npx hardhat verify --network mode-testnet <deployed address>
You should see an output similar to:
Blockscout
Successfully submitted source code for contract
contracts/NFT.sol:NFT at 0xFcd93C541F12762dFB98719Ce47456E328C8488a
for verification on the block explorer. Waiting for verification result...
Successfully verified contract NFT on the block explorer.
https://sepolia.explorer.mode.network/address/0xFcd93C541F12762dFB98719Ce47456E328C8488a#code
INFO
You can’t re-verify a contract identical to one that has already been verified. If you attempt to do so, such as verifying the above contract, you’ll get an error similar to:
Error in plugin @nomiclabs/hardhat-etherscan: The API responded with an unexpected message.
Contract verification may have succeeded and should be checked manually.
Message: Already Verified
Search for your contract on Blockscout to confirm it verified .
Interacting with the Smart Contract
If you verified on Blockscout, you can use the Read Contract
and Write Contract
tabs to interact with the deployed contract. You'll need to connect your wallet first, by clicking the Connect button.