Setting up Github Actions with Hardhat
Learn how to configure a GitHub Action to set up a Continuous Integration and Continuous Deployment pipeline (CI/CD) with Hardhat on Virtual TestNets.
Use the Tenderly Virtual TestNet Setup to enable automated builds that test your contracts. After successful testing, you can stage them for the rest of your team by deploying them the provisioned Virtual Testnet.
In this guide, you need to complete two stages:
- Local setup: Set up Hardhat and create and test the workflow file.
- Github setup: Set up a GitHub Action, configure GitHub secrets and variables, and test the build.
For reference, use this example project:
This guide demonstrates a CI setup that relies on Hardhat-ignition. For hardhat-verify
setup, the process and configuration are similar.
Local setup
First, we’ll install necessary dependencies and create a workflow file.
Install dependencies
Make sure you have the following package installed to get automatic contract verification:
@tenderly/hardhat-tenderly
Create the workflow file
To set up the GitHub Action, create a new workflow:
mkdir -p .github/workflows
touch ci-cd.yaml
Next, paste the following yaml file that configures two steps:
test
step to run hardhat tests usingtest:vnet
command defined inpackage.json
. This step uses a fresh testnet to run tests against, and pauses the testnet after completion, taking it to read-only mode.deploy
step to deploy contracts usingdeploy:vnet
command defined inpackage.json
. This step creates a fresh testnet, stages contracts to it, and keeps it alive for further development.
The mode
argument takes values CI
and CD
.
- The
CD
mode keeps the Virtual TestNet active and you can work with deployed contracts. - The
CI
mode pauses the Virtual TestNet after the step completes. You’ll be able to inspect transactions but won’t be able to send further RPC requests.
name: Hardhat CI/CD
on: [push, pull_request]
env:
DEBUG: '@tenderly/github-action'
## Needed available as env variables for hardhat.config.js
TENDERLY_PROJECT_NAME: ${{ vars.TENDERLY_PROJECT_NAME }}
TENDERLY_ACCOUNT_NAME: ${{ vars.TENDERLY_ACCOUNT_NAME }}
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Setup Virtual TestNet
uses: Tenderly/vnet-github-action@V1.0.11
with:
mode: CI
access_key: ${{ secrets.TENDERLY_ACCESS_KEY }}
project_name: ${{ vars.TENDERLY_PROJECT_NAME }}
account_name: ${{ vars.TENDERLY_ACCOUNT_NAME }}
testnet_name: "Testing"
network_id: 1
chain_id: 1
state_sync: true
public_explorer: true
verification_visibility: bytecode
- name: Install dependencies
run: npm install
- name: Run Tests
run: npm run test:vnet
deploy:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Setup Virtual TestNet
uses: Tenderly/vnet-github-action@V1.0.11
with:
mode: CD
access_key: ${{ secrets.TENDERLY_ACCESS_KEY }}
project_name: ${{ vars.TENDERLY_PROJECT_NAME }}
account_name: ${{ vars.TENDERLY_ACCOUNT_NAME }}
testnet_name: "Staging"
network_id: 1
chain_id: 1 # custom chain ID
state_sync: true
public_explorer: true
verification_visibility: bytecode
- name: Install dependencies
run: npm install
- name: Deploy Contracts
run: npm run deploy:vnet
Prepare environment variables
For local testing, set up an .env
file using this template:
## Virtual TestNet config
## Paste your local development version
TENDERLY_CHAIN_ID=...
TENDERLY_ADMIN_RPC_URL=...
## Access parameters
TENDERLY_ACCESS_KEY=...
TENDERLY_PROJECT_NAME=...
TENDERLY_ACCOUNT_NAME=...
TENDERLY_CHAIN_ID
: The Chain ID assigned to the Virtual TestNet you created.TENDERLY_ADMIN_RPC_URL
: The Admin RPC of your Virtual TestNet.TENDERLY_ACCESS_KEY
: Learn how to get your access key.TENDERLY_ACCOUNT_NAME
andTENDERLY_PROJECT_NAME
: Follow a few steps to get your account and project name.
Configure Hardhat
Add the Virtual TestNet configuration to hardhat.config.ts
:
import { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox";
import "@tenderly/hardhat-tenderly";
import * as dotenv from 'dotenv';
dotenv.config();
const config: HardhatUserConfig = {
solidity: "0.8.27",
networks: {
tenderly_ci: {
url: process.env.TENDERLY_ADMIN_RPC_URL,
chainId: parseInt(process.env.TENDERLY_CHAIN_ID!)
},
},
etherscan: {
apiKey: {
tenderly_ci: process.env.TENDERLY_ACCESS_KEY!
},
customChains: [
{
network: "tenderly_ci",
chainId: parseInt(process.env.TENDERLY_CHAIN_ID!),
urls: {
apiURL: `${process.env.TENDERLY_ADMIN_RPC_URL}/verify/etherscan`,
browserURL: process.env.TENDERLY_ADMIN_RPC_URL!
}
}
]
},
tenderly: {
project: process.env.TENDERLY_PROJECT_NAME!,
username: process.env.TENDERLY_ACCOUNT_NAME!,
accessKey: process.env.TENDERLY_ACCESS_KEY!
},
sourcify: {
enabled: false
}
};
Add test and deploy scripts
Extend package.json
with the following scripts that your workflow uses to test and stage contracts on the tenderly_ci
network.
{
"scripts": {
"deploy:vnet": "yes | npx hardhat ignition deploy ./ignition/modules/Counter.js --network tenderly_ci --deployment-id deploy",
"test:vnet": "npx hardhat test --network tenderly_ci"
}
}
Test the build locally
To test the build locally, run the following command:
npx hardhat test:vnet
npx hardhat deploy:vnet
Test the Github Action locally
To test your action locally, you can use Act, the local task runner for GitHub Actions.
act --secret-file .env --var-file .env
Github Setup
After successful local setup, proceed by configuring Github with environment variables and necessary secrets.
Configure secrets and environment variables in GitHub
You must configure the following Github variables and one secret. Use the values from the .env file you’ve set up previously.
TENDERLY_PROJECT_NAME
as a variableTENDERLY_ACCOUNT_NAME
as a variableTENDERLY_ACCESS_KEY
as a secret
You can achieve this via the GitHub UI or using the gh
command line:
source .env
gh variable set TENDERLY_PROJECT_NAME --body ${TENDERLY_PROJECT_NAME}
gh variable set TENDERLY_ACCOUNT_NAME --body ${TENDERLY_ACCOUNT_NAME}
gh secret set TENDERLY_ACCESS_KEY --body ${TENDERLY_ACCESS_KEY}
Push the updates
To see the GitHub Action run, simply push the updates:
git add .
git commit -m "Adds CI/CD workflow"
git push