How to automate a headache-free deployment with Hardhat Ignition

Hardhat Ignition is a declarative system for deploying smart contracts on Ethereum. It enables you to define smart contract instances you…

How to automate a headache-free deployment with Hardhat Ignition

Hardhat Ignition is a declarative system for deploying smart contracts on Ethereum. It enables you to define smart contract instances you want to deploy, and any operation you want to run on them. By taking over the deployment and execution, Hardhat Ignition lets you focus on your project instead of getting caught up in the deployment execution details. It’s a better end-to-end deployment experience. To learn more, check out our announcement post.

Let’s get started and look into how you can automate a simple deployment using Hardhat Ignition.

Installation

We’re going to quickly install Hardhat, set up a new project, and install Hardhat Ignition. Skip to the next section if you know how to do this already!

Open a terminal and execute the following commands to set up an NPM project with Hardhat:

mkdir hardhat-ignition-tutorial/ 
cd hardhat-ignition-tutorial 
npm init 
npm install --save-dev hardhat

Then run npx hardhat init, select “Create a TypeScript project” and “yes” in the following steps. Our Hardhat project is now ready, and we’re going to install Hardhat Ignition next. Run:

npm install --save-dev @nomicfoundation/hardhat-ignition

Finally, open the hardhat.config.ts file and add this line at the top to enable the plugin:

import "@nomicfoundation/hardhat-ignition";

Creating your contract

Paste the following code into contracts/Rocket.sol:

// SPDX-License-Identifier: UNLICENSED 
pragma solidity ^0.8.0; 
 
contract Rocket { 
    string public name; 
    string public status; 
 
    constructor(string memory _name) { 
        name = _name; 
        status = "ignition"; 
    } 
 
    function launch() public { 
        status = "lift-off"; 
    } 
}

It contains a simple smart contract called Rocket, featuring a launch function that we'll call after deployment.

Creating your first module

In Hardhat Ignition, deployments are expressed through Ignition Modules. These modules are defined in JavaScript/Typescript and let you outline and describe the system that you want to deploy.

Modules are declared in JavaScript or Typescript files inside of ignition/modules. Let's create that folder structure:

mkdir ignition 
mkdir ignition/modules

And paste the following code into a ignition/modules/Apollo.ts. We'll explain it in a moment.

import { buildModule } from "@nomicfoundation/hardhat-ignition/modules"; 
 
export default buildModule("Apollo", (m) => { 
  const apollo = m.contract("Rocket", ["Saturn V"]); 
 
  m.call(apollo, "launch", []); 
 
  return { apollo }; 
});

The first aspect to note is that modules are created by calling the buildModule function, which requires a module ID and a callback function. Our module will be identified as "Apollo".

The callback function is where the module definition actually happens. The m parameter being passed into the callback is an instance of a ModuleBuilder, which is an object with methods to define and configure your smart contract instances.

When we call these ModuleBuilder methods, they create a Future object, which represents the result of an execution step that Hardhat Ignition needs to run to deploy a contract instance or interact with an existing one.

This doesn't execute anything against the network, it simply represents it internally. After the Future is created, it gets registered within the module, and the method returns it.

In our module, we created two Future objects by calling the contract and call methods. The initial one instructs Hardhat Ignition to deploy a Rocket contract instance, specifying "Saturn V" as the only constructor parameter. The second one indicates that we intend to execute the launch function of the deployed Rocket instance, with no arguments provided.

Finally, we return the Future object representing the Rocket contract instance, to make it accessible to other modules and tests as well.

Deploying it

Now that our module definition is ready, let's deploy it to a local Hardhat node. Let's start by spinning up a local node:

npx hardhat node

Next, in a separate terminal in the root of your Hardhat project, run:

npx hardhat ignition deploy ignition/modules/Apollo.ts --network localhost

Hardhat Ignition will execute every Future that we defined in the right order, and display the results:

Hardhat Ignition 🚀 
 
Deploying [ Apollo ] 
 
Batch #1 
  Executed Apollo#Rocket 
 
Batch #2 
  Executed Apollo#Rocket.launch 
 
[ Apollo ] successfully deployed 🚀 
 
Deployed Addresses 
 
Apollo#Rocket - 0x5fbdb2315678afecb367f032d93f642f64180aa3

An ignition/deployments/chain-31337 folder will have been created. It contains all the details about your deployment. Hardhat Ignition uses this data to recover from errors, resume a modified deployment, and more.

That's all it takes to define and execute a deployment using Hardhat Ignition!

Check it out

For an in-depth guide on everything you can express with modules, see Creating Ignition Modules on our documentation site. We designed this tool for sophisticated users, which means there’s a lot more that is possible.

We’d love to hear your feedback, so give it a try! Here are some useful links:

If you like Hardhat Ignition, please star the repo on Github, and let us know what you think!