CI/CD Pipeline for Smart Contracts

Overview

You will see how to set up Github Actions with Tenderly Forks in order to achieve automated smart contract testing and staging deployment. We are going to showcase how to start from an empty project and end up with a valid CI/CD for your project. So, what are we going to do?
Automatically run smart contract tests on top of production network data:
  1. 1.
    Setup smart contract project infra.
  2. 2.
    Create testing Github Actions YAML file.
  3. 3.
    Inject Tenderly Fork in the test process.
Automatically create staging FE environment for PRs:
  1. 1.
    Create Github Action for FE web hosting.
  2. 2.
    Inject Tenderly Fork in the build process.

Automatically run smart contract tests on top production network data

Setup smart contract project infra

Let’s create a dummy solidity smart contract project and some dummy tests using Hardhat. We can utilize Hardhat’s quick start guide in order to achieve this:
Ethereum development environment for professionals
HardhatHQ
Additionally, we are going to extend networks with Tenderly Fork specification, for the example below:
Hardhat config:
1
import "@nomiclabs/hardhat-waffle";
2
import "@tenderly/hardhat-tenderly";
3
import "dotenv/config";
4
​
5
const {
6
TENDERLY_FORK_URL
7
} = process.env
8
​
9
export default {
10
solidity: "0.8.4",
11
networks: {
12
"tenderly-fork": {
13
url: TENDERLY_FORK_URL
14
},
15
},
16
};
Copied!
package.json
1
...
2
"scripts": {
3
"test": "npx hardhat test",
4
"test:ci": "npx hardhat test --network tenderly-fork"
5
},
6
...
Copied!

Create testing Github Action Workflow YAML file

Let's see how we can set up our Github Action in order to run our tests:
1
name: Run tests in Tenderly Fork
2
​
3
on:
4
push:
5
branches: [ main ]
6
pull_request:
7
branches: [ main ]
8
jobs:
9
test:
10
name: Test hardhat-core on Ubuntu with Node ${{ matrix.node }}
11
runs-on: ubuntu-latest
12
defaults:
13
run:
14
working-directory: ./ci-cd-pipeline-for-smart-contracts/smart-contract-pipeline
15
strategy:
16
matrix:
17
node: [ 16 ]
18
steps:
19
- uses: actions/[email protected]
20
- uses: actions/setup-[email protected]
21
with:
22
node-version: ${{ matrix.node }}
23
- uses: actions/[email protected]
24
with:
25
path: '**/node_modules'
26
key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}
27
- name: Install
28
run: yarn install
29
- name: Run tests
30
run: yarn test
Copied!

Inject Tenderly Fork into the test process

And finally, let’s see how we can inject a Tenderly Fork into our CI pipeline.
1
...
2
- name: Run test on fork
3
run: yarn test:ci
4
env:
5
JSON_RPC_URL: ${{ secrets.TENDERLY_FORK_URL }}
Copied!
And we are done! 🎉

Automatically create staging FE environment for PRs

Create Github Action for web hosting

Let’s create an action that would store the build distribution of our React application on the Google Cloud Storage bucket so we can access it later.
We will need GCP_CREDENTIALS which you can generate using the command below and you should store as part of GitHub secrets.
1
gcloud iam service-accounts keys create ~/key.json --iam-account <iam-name>@<project-id>.iam.gserviceaccount.com
Copied!
Github Action YAML
1
name: Build and deploy staging to google could storage
2
on:
3
pull_request:
4
branches: [ main ]
5
jobs:
6
build-deploy:
7
runs-on: ubuntu-latest
8
defaults:
9
run:
10
working-directory: ./ci-cd-pipeline-for-smart-contracts/front-end-cd
11
strategy:
12
matrix:
13
node: [ 16 ]
14
steps:
15
- uses: actions/[email protected]
16
- uses: actions/setup-[email protected]
17
with:
18
node-version: ${{ matrix.node }}
19
- uses: actions/[email protected]
20
with:
21
path: '**/node_modules'
22
key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}
23
- id: 'auth'
24
uses: 'google-github-actions/[email protected]'
25
with:
26
credentials_json: '${{ secrets.GCP_CREDENTIALS }}'
27
- name: 'Set up Cloud SDK'
28
uses: 'google-github-actions/[email protected]'
29
- name: Build React App
30
run: yarn install && yarn run build
31
- name: Deploy app build to GCS bucket
32
run: |-
33
gsutil -m rsync -R ./build gs://${{secrets.GCS_BUCKET}}/${{github.run_id}}
Copied!

Inject Tenderly Fork into the build process

Now that we have our GitHub Action ready to roll, let’s edit it a bit in order to be aware of Tenderly Forks.
1
...
2
- name: Build React App
3
run: yarn install && yarn run build:cd
4
env:
5
TENDERLY_FORK_URL: ${{ secrets.TENDERLY_FORK_URL }}
6
REACT_APP_ENV: staging
7
...
Copied!
Here are the links to the source code and also GitHub Actions YAML.