Join the Hardhat team! We are hiring

#4. Writing and compiling smart contracts

We're going to create a simple smart contract that implements a token that can be transferred. Token contracts are most frequently used to exchange or store value. We won't go in depth into the Solidity code of the contract on this tutorial, but there's some logic we implemented that you should know:

  • There is a fixed total supply of tokens that can't be changed.
  • The entire supply is assigned to the address that deploys the contract.
  • Anyone can receive tokens.
  • Anyone with at least one token can transfer tokens.
  • The token is non-divisible. You can transfer 1, 2, 3 or 37 tokens but not 2.5.


You might have heard about ERC20, which is a token standard in Ethereum. Tokens such as DAI, USDC, MKR and ZRX follow the ERC20 standard which allows them all to be compatible with any software that can deal with ERC20 tokens. For simplicity's sake the token we're going to build is not an ERC20.

# Writing smart contracts

Start by creating a new directory called contracts and create a file inside the directory called Token.sol.

Paste the code below into the file and take a minute to read the code. It's simple and it's full of comments explaining the basics of Solidity.


To get syntax highlighting you should add Solidity support to your text editor. Just look for Solidity or Ethereum plugins. We recommend using Visual Studio Code or Sublime Text 3.

// Solidity files have to start with this pragma.
// It will be used by the Solidity compiler to validate its version.
pragma solidity ^0.7.0;

// This is the main building block for smart contracts.
contract Token {
    // Some string type variables to identify the token.
    // The `public` modifier makes a variable readable from outside the contract.
    string public name = "My Hardhat Token";
    string public symbol = "MHT";

    // The fixed amount of tokens stored in an unsigned integer type variable.
    uint256 public totalSupply = 1000000;

    // An address type variable is used to store ethereum accounts.
    address public owner;

    // A mapping is a key/value map. Here we store each account balance.
    mapping(address => uint256) balances;

     * Contract initialization.
     * The `constructor` is executed only once when the contract is created.
    constructor() {
        // The totalSupply is assigned to transaction sender, which is the account
        // that is deploying the contract.
        balances[msg.sender] = totalSupply;
        owner = msg.sender;

     * A function to transfer tokens.
     * The `external` modifier makes a function *only* callable from outside
     * the contract.
    function transfer(address to, uint256 amount) external {
        // Check if the transaction sender has enough tokens.
        // If `require`'s first argument evaluates to `false` then the
        // transaction will revert.
        require(balances[msg.sender] >= amount, "Not enough tokens");

        // Transfer the amount.
        balances[msg.sender] -= amount;
        balances[to] += amount;

     * Read only function to retrieve the token balance of a given account.
     * The `view` modifier indicates that it doesn't modify the contract's
     * state, which allows us to call it without executing a transaction.
    function balanceOf(address account) external view returns (uint256) {
        return balances[account];


*.sol is used for Solidity files. We recommend matching the file name to the contract it contains, which is a common practice.

# Compiling contracts

To compile the contract run npx hardhat compile in your terminal. The compile task is one of the built-in tasks.

$ npx hardhat compile
Compiling 1 file with 0.7.3
Compilation finished successfully

The contract has been successfully compiled and it's ready to be used.