Setting up Github Actions with Foundry
Learn how to configure a GitHub Action to set up a Continuous Integration and Continuous Deployment pipeline (CI/CD) with Foundry on Tenderly Virtual TestNets.
Use the Tenderly Virtual TestNet Setup action to enable automated builds that test your contracts. After successful testing, you can stage them for the rest of your team by deploying them to the provisioned Virtual TestNet.
In this guide, you need to complete two stages:
- Local setup: Set up Foundry and create and test out 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:
Local Setup
First, we’ll create a workflow file and necessary settings.
Create the Workflow File
In your foundry project, create a new workflows
directory and ci-cd.yaml
:
mkdir -p .github/workflows
touch .github/workflows/ci-cd.yaml
Next, paste the following configuration to ci-cd.yaml
that sets up two jobs:
test
job to run Foundry testsdeploy
job to deploy contracts to a staging Virtual TestNet
This sample workflow file does several things:
- Uses
Tenderly/vnet-github-action
to provision a Virtual TestNet based on givennetwork
, with customchain_id
. - Updates
foundry.toml
with correct chain ID (especially important if you’re using a custom chain_id), and passing verification information. - Funds the
DEPLOYER_WALLET_ADDRESS
EOA with 100 ETH. - Deploys the contracts using the Virt
name: Foundry CI/CD
on:
push:
pull_request:
workflow_dispatch:
env:
TENDERLY_ACCESS_KEY: ${{ secrets.TENDERLY_ACCESS_KEY }}
DEBUG: '@tenderly/github-action'
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
- name: Build and Test
working-directory: ./examples/foundry
run: |
forge build
forge test -vvv
deploy:
needs: test
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- 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: 73571 # custom chain ID
public_explorer: true
verification_visibility: 'src'
- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
- name: Foundry Build
working-directory: ./examples/foundry
run: |
sed -e "s|\${TENDERLY_ACCESS_KEY}|$TENDERLY_ACCESS_KEY|g" \
-e "s|\${TENDERLY_FOUNDRY_VERIFICATION_URL}|$TENDERLY_FOUNDRY_VERIFICATION_URL|g" \
-e "s/\(unknown_chain[[:space:]]*=[[:space:]]*{[^}]*chain[[:space:]]*=[[:space:]]*\)[0-9][0-9]*/\1$TENDERLY_CHAIN_ID/g" \
foundry.toml > foundry.toml.tmp && mv foundry.toml.tmp foundry.toml
forge --version
forge build --sizes
- name: Fund Wallet
run: |
curl --location "${{ env.TENDERLY_ADMIN_RPC_URL }}" \
--header 'Content-Type: application/json' \
--data @- << EOF
{
"jsonrpc": "2.0",
"method": "tenderly_setBalance",
"params": ["${{ secrets.DEPLOYER_WALLET_ADDRESS }}", "0xDE0B6B3A7640000"],
"id": "1"
}
EOF
- name: Deploy Contracts
working-directory: ./examples/foundry
run: |
forge script script/Counter.s.sol \
--private-key ${{ secrets.DEPLOYER_PRIVATE_KEY }} \
--rpc-url ${{ env.TENDERLY_PUBLIC_RPC_URL }} \
--verifier-url ${{ env.TENDERLY_FOUNDRY_VERIFICATION_URL }} \
--etherscan-api-key $TENDERLY_ACCESS_KEY \
--slow \
--broadcast \
--verify
Configure Foundry
Create or update your foundry.toml
configuration file. To benefit from automatic contract verification you must have the unknown_chain
entry with key
, chain
, url
.
When using Virtual TestNets from your local machine, replace the chain = 0
with the chain ID of the virtual testnet you connected to.
[profile.default]
src = "src"
out = "out"
libs = ["lib"]
cbor_metadata = true
# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options
[etherscan]
## placeholders must be replaced with key ("string"), chain_id (number, non-quoted), and tenderly_foundry_verification_url ("string")
unknown_chain = { key = "$TENDERLY_ACCESS_KEY", chain = 0, url = "$TENDERLY_FOUNDRY_VERIFICATION_URL" }
Prepare Environment Variables
For local testing, set up an .env
file with the following variables:
# Access parameters
TENDERLY_ACCESS_KEY=...
TENDERLY_PROJECT_NAME=...
TENDERLY_ACCOUNT_NAME=...
# Deployment parameters
DEPLOYER_PRIVATE_KEY=...
DEPLOYER_WALLET_ADDRESS=...
Required variables:
TENDERLY_ACCESS_KEY
: Your Tenderly access keyTENDERLY_ACCOUNT_NAME
andTENDERLY_PROJECT_NAME
: Your account and project namesDEPLOYER_PRIVATE_KEY
: Private key for the deployment walletDEPLOYER_WALLET_ADDRESS
: Address corresponding to the private key
Test Locally
To test your setup locally:
- Build and test the contracts:
source .env
forge build
forge test
- Fund the deployer wallet and deploy the contracts
curl --location "${{ env.TENDERLY_ADMIN_RPC_URL }}" \
--header 'Content-Type: application/json' \
--data @- << EOF
{
"jsonrpc": "2.0",
"method": "tenderly_setBalance",
"params": ["${{ secrets.DEPLOYER_WALLET_ADDRESS }}", "0xDE0B6B3A7640000"],
"id": "1"
}
EOF
forge script script/Counter.s.sol \
--private-key ${{ secrets.DEPLOYER_PRIVATE_KEY }} \
--rpc-url ${{ env.TENDERLY_PUBLIC_RPC_URL }} \
--verifier-url ${{ env.TENDERLY_FOUNDRY_VERIFICATION_URL }} \
--etherscan-api-key $TENDERLY_ACCESS_KEY \
--slow \
--broadcast \
--verify
Test the Github Action Locally
You can test your GitHub Action locally using Act without pushing to Github.
Use the .env
file to populate Github secrets and environment variables as follows:
act --secret-file .env --var-file .env
Github Setup
After confirming your local setup works, configure your GitHub repository.
Configure Secrets and Variables
Set up the following GitHub secrets and variables:
Secrets:
TENDERLY_ACCESS_KEY
: the Tenderly Access KeyDEPLOYER_PRIVATE_KEY
: the private key for the deployer EOA
Variables:
TENDERLY_PROJECT_NAME
: the Tenderly project nameTENDERLY_ACCOUNT_NAME
: the project’s owner’s nameDEPLOYER_WALLET_ADDRESS
: the deployer EOA
You can achieve this via the GitHub UI or using the gh
command line:
# Load environment variables
source .env
# Set variables
gh variable set TENDERLY_PROJECT_NAME --body ${TENDERLY_PROJECT_NAME}
gh variable set TENDERLY_ACCOUNT_NAME --body ${TENDERLY_ACCOUNT_NAME}
gh variable set DEPLOYER_WALLET_ADDRESS --body ${DEPLOYER_WALLET_ADDRESS}
# Set secrets
gh secret set TENDERLY_ACCESS_KEY --body ${TENDERLY_ACCESS_KEY}
gh secret set DEPLOYER_PRIVATE_KEY --body ${DEPLOYER_PRIVATE_KEY}
Push the Updates
Finally, commit and push your changes:
git add .
git commit -m "Add CI/CD workflow for Foundry"
git push