Cronos: Dutch auction smart contract with Hardhat
A Dutch auction is a type of an auction in which the initial price of an NFT starts at its ceiling and lowers by a small amount at set intervals. Buyers make bids at reduced prices until the end of an auction. A Dutch auction continues until either all assets are sold out or the auction time ends.
The objective of this tutorial is to familiarize you with the Cronos network, Hardhat, and Dutch auction smart contracts. In the end of the tutorial, you will be able to create a simple Dutch auction smart contract to help you sell your NFTs to the highest bidder.
Specifically, in this tutorial, you will:
- Create a Dutch auction smart contract.
- Deploy and verify the contract on the Cronos testnet through a node deployed with Chainstack.
- Interact with the deployed contract.
Prerequisites
- Chainstack account to deploy a Cronos testnet node.
- Hardhat to compile and deploy the contract.
- MetaMask to interact with the contract through your Chainstack node.
Overview
To get from zero to deploying your own Dutch auction smart contract on the Cronos testnet, do the following:
- With Chainstack, create a public chain project.
- With Chainstack, join the Cronos testnet.
- With Chainstack, access your Cronos node endpoint.
- With Hardhat, set up your development environment.
- With Hardhat, create and compile your Dutch auction contract.
- With MetaMask, fund your wallet with Cronos test tokens (CRO) from the Cronos official faucet.
- With Hardhat, deploy your Dutch auction contract.
- With Cronos testnet explorer, interact with your Dutch auction contract.
Step-by-step
Create a public chain project
See Create a project.
Join the Cronos testnet
Get your Cronos node endpoint
See View node access and credentials.
Install Hardhat
Initialize a Hardhat project
In your project directory, run npx hardhat
. Select Create a JavaScript project and agree to install the sample project's dependencies. This will create a sample project directory with a smart contract draft.
Install additional dependencies
To complete the project, we need to install several additional dependencies.
The OpenZeppelin Contract library allows you to inherit smart contracts. To install it, run:
npm i @openzeppelin/contracts
The dotenv library allows you to export and keep sensitive data securely. To install it, run:
npm i dotenv
The hardhat-etherscan and hardhat-cronoscan plugins allow you to verify your contracts on the Cronos testnet. To install them, run:
npm i --save-dev @nomiclabs/hardhat-etherscan@^3.1.0 @cronos-labs/hardhat-cronoscan
You need to create an environment file to store your sensitive data with the project. To create it, in your project directory, run:
touch .env
Create and compile the contract
-
Navigate to your previously created project directory and go to the
contracts
directory. In the directory, create your Dutch auction smart contract:DutchAuction.sol
.// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/utils/Counters.sol"; contract MyToken is ERC721, Ownable { using Counters for Counters.Counter; Counters.Counter private _tokenIdCounter; uint256 public immutable startPrice = 10 ether; uint256 public immutable startAt; uint256 public immutable endsAt; uint256 public immutable endPrice = 5 ether; uint256 public immutable discountRate = 0.01 ether; uint256 public duration = 500 minutes; uint256 public immutable MAX_SUPPLY = 100; mapping (address => bool) public onlyOne; constructor() ERC721("CronosNFT", "CroNFT") { startAt = block.timestamp; endsAt = block.timestamp + duration; } function price() public view returns (uint256) { if (block.timestamp > endsAt ) { return endPrice; } uint256 minutesElapsed = (block.timestamp - startAt) / 60; return startPrice - (minutesElapsed * discountRate); } function safeMint(address to) public payable { require(msg.value >= price(), "Not enough ether sent"); require(!onlyOne[msg.sender], "Sorry, Address already has 1 NFT!"); uint256 tokenId = _tokenIdCounter.current(); require(tokenId < MAX_SUPPLY, "No more items left."); _safeMint(to, tokenId + 1); _tokenIdCounter.increment(); onlyOne[msg.sender]=true; } function withdraw() public onlyOwner { payable(owner()).transfer(address(this).balance); } }
The contract implementation is the following:
- The price of an NFT starts at 10 ether and decreases to 5 ether over 500 minutes. A maximum of 100 NFTs can be minted.
- The contract uses the
onlyOne
mapping to ensure that each address can only own one NFT from your collection. - The contract sets the values of the start and end price, which cannot be changed later on.
- The function
price()
usesblock.timestamp
to calculate the price of an NFT each time thesafeMint
function is called. - If all the required conditions are satisfied, the wallet address gets an NFT minted.
-
To compile the contract, in your project directory, run:
npx hardhat compile
Fund your account
To deploy your smart contract on the Cronos testnet, you will need some test CRO. See the Cronos faucet.
Set up the environment and configuration files
-
In your project directory, navigate to a previously created environment file and edit it to add the following data:
RPC_URL
— your Cronos node HTTPS endpoint deployed with Chainstack. See also View node access and credentials.PRIVATE_KEY
— the private key of your MetaMask wallet that has a sufficient amount of TCRO. See also the Cronos faucet.API_KEY
— a Cronos API key to verify the deployed smart contract using the Cronoscan and Etherscan plugins. Create an API key in the Cronos blockchain explorer.
Example of the environment file data:
RPC_URL=YOUR_CHAINSTACK_ENDPOINT PRIVATE_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXu7 API_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXG5
-
In your project directory, navigate to the Hardhat configuration file and replace the current data with the following data:
require("@nomicfoundation/hardhat-toolbox"); require('dotenv').config(); require("@nomiclabs/hardhat-etherscan"); require("@cronos-labs/hardhat-cronoscan"); module.exports = { solidity: "0.8.10", networks: { Cronos_testnet: { url: `${process.env.RPC_URL}`, accounts: [process.env.PRIVATE_KEY] }, }, etherscan: { apiKey: { cronosTestnet: `${process.env.API_KEY}`, }, }, };
where
dotenv
— library to import your sensitive data from the environment file securelyCronos_testnet
— the testnet to deploy the contract tourl
— your Cronos node HTTPS endpoint imported from the environment fileaccounts
— your MetaMask wallet private key imported from the environment fileetherscan
— your Cronos API key imported from the environment file to verify your contract
Deploy the Dutch auction contract
-
In your project directory, navigate to the scripts directory and create the
DeployDutch.js
file. -
Edit the
DeployDutch.js
file to add the basic deployment script of Hardhat:const hre = require("hardhat"); async function main() { const CronosToken = await hre.ethers.getContractFactory("MyToken"); console.log("Deploying your contract, please Wait....."); const cronosToken = await CronosToken.deploy(); await cronosToken.deployed(); console.log("CronosToken deployed to:", cronosToken.address); } main() .then(() => process.exit(0)) .catch((error) => { console.error(error); process.exit(1); });
-
In your project directory, run the following script:
npx hardhat run scripts/DeployDutch.js --network Cronos_testnet
The contract will deploy and the terminal will return the contract address. Use this address to verify and interact with your contract.
Verify your contract on the Cronos testnet
Once your contract is deployed, verify it on the Cronos testnet. In your terminal, run:
npx hardhat verify --network Cronos_testnet CONTRACT_ADDRESS
where CONTRACT_ADDRESS your contract address returned at the previous step
Interact with the contract
Now that your contract is verified, Cronoscan is effectively a front-end instance for your contract.
Conclusion
This tutorial guided you through the basics of using Hardhat to deploy a Dutch auction smart contract to the Cronos testnet, and verify it using Etherscan and Cronoscan plugins.
This tutorial uses testnet, however, the exact same instructions and sequence work on the mainnet.
About the author
Updated about 1 year ago