In this tutorial, you’ll learn how to create and manage an advanced ERC-721 token smart contract using Hardhat and OpenZeppelin. We’ll cover deploying the contract, minting NFTs, pausing and unpausing the contract, and transferring tokens. You’ll gain experience with Access Control (admin, minting, pausing roles), URI storage, and Pausable functionalities.Documentation Index
Fetch the complete documentation index at: https://hedera-0c6e0218-514-egress-ports.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
You can take a look at the complete code in the Hedera-Code-Snippets
repository.
Prerequisites
- ⚠️ Complete tutorial part 1 as we continue from this example.
- Basic understanding of smart contracts.
- Basic understanding of Node.js and JavaScript.
- Basic understanding of Hardhat EVM Development Tool and Ethers.
- ECDSA account from the Hedera Portal.
Table of Contents
- Create and Compile the Solidity Contract
- Deploying the Smart Contract and Minting a Token
- Fixing Permissions, Redeploying, and Minting
- Pausing the ContractPausing the Contract
- Transferring NFTs
- Run tests
Video Tutorial
You can watch the video tutorial (which uses Hardhat version 2) or follow the step-by-step tutorial below (which uses Hardhat version 3).🚧 What's new: Hardhat 2 → 3
🚧 What's new: Hardhat 2 → 3
Key differences in Hardhat 3:
- compile → build
npx hardhat compileis nownpx hardhat build. This is the big one. The v3 migration guide explicitly shows using thebuildtask. - project init switch
v2 commonly usednpx hardhatornpx hardhat initto bootstrap. In v3 it’snpx hardhat --init.
- keystore helper commands are new
v3’s recommended flow includes a keystore plugin with commands likenpx hardhat keystore set HEDERA_RPC_URLandnpx hardhat keystore set HEDERA_PRIVATE_KEY. These weren’t standard in v2. - Foundry-compatiable Solidity tests
In addition to offering Javascript/Typescript integration tests, Hardhat v3 also integrates Foundry-compatible Solidity tests that allows developers to write unit tests directly in Solidity
- Enhanced Network Management
v3 allows tasks to create and manage multiple network connections simultaneously which is a significant improvement over the single, fixed connection available in version 2. This provides greater flexibility for scripts and tests that interact with multiple networks.
Step 1: Create and Compile the Solidity Contract
Create a new Solidity file namedMyTokenAdvanced.sol in your contracts directory, and paste this Solidity code:
contracts/MyTokenAdvanced.sol
ERC721URIStorage, ERC721Pausable, and AccessControl interfaces from OpenZeppelin. You can create the contract yourself using the OpenZeppelin Wizard and enable “Mintable,” “Pausable,” “URI Storage,” and “Access Control → Roles.”
Compile your new contract:
Step 2: Deploying the Smart Contract and Minting a Token
Createdeploy-advanced.ts in your scripts folder:
scripts/deploy-advanced.ts
MyTokenAdvanced.deploy() function. When we look at the constructor of our smart contract, we can provide the admin, pauser, and minter roles.
deploy-advanced.ts script sets the minter role to an unknown (random) address. This should prevent the deployer account from minting new tokens in the next step. First, let’s run the deployer script:
mint-advanced.ts in your scripts folder:
scripts/mint-advanced.ts
https://myserver.com/8bitbeard/8bitbeard-tokens/tokens/1 . This transaction will fail because our deployer account doesn’t have the minter permission. Run the script:
Step 3: Fixing Permissions, Redeploying, and Minting
Update the minting role to your deployer account by modifying the following line of code in yourdeploy-advanced.ts script:
scripts/deploy-advanced.ts
contractAddress variable in your mint-advanced.ts script with this new address.
Next, execute the minting logic:
0 and the corresponding token URI is printed to your terminal.
Step 4: Pausing the Contract
Create a newpause-advanced.ts script and make sure to replace the contractAddress variable with your address:
scripts/pause-advanced.ts
true when it is paused. Now, nobody can mint new tokens.
Pausing an ERC-721 contract temporarily disables critical functions, including
minting, transferring, and burning tokens. While the contract is paused, users
cannot perform these operations, making it particularly useful in emergency
scenarios or maintenance periods. However, read operations, such as checking
token balances or URIs, are still possible.
Step 5: Transferring NFTs
Create atransfer-advanced.ts script to transfer an NFT to another address. Don’t forget to replace the contractAddress with your smart contract address.
scripts/transfer-advanced.ts
0x5FbDB2315678afecb367f032d93F642f64180aa3 using the transferFrom function on your contract. This function accepts the sender address, receiver address, and the token ID you want to transfer. Next, we check if the account has actually received the token by verifying its balance.
Execute the script to transfer the token:
0x5FbDB2315678afecb367f032d93F642f64180aa3**account shows 1 , then you’ve successfully transferred the NFT and completed this tutorial! 🎉
Step 6: Run tests(Optional)
You can find both types of tests in the Hedera-Code-Snippets repository. You will find the following files:contracts/MyTokenAdvanced.t.soltest/MyTokenAdvanced.ts