Skip to content

refactor: change brand to imua (#150) #506

refactor: change brand to imua (#150)

refactor: change brand to imua (#150) #506

Workflow file for this run

name: Forge CI
on:
merge_group:
pull_request:
push:
branches:
- main
- release/**
tags:
- "*"
concurrency:
# cancel the other workflows on the same PR
# we do not do the same for any of the `workflow_run` triggered CI despite the possibility because
# (1) it is complicated to set up, since the PR number is not available directly in that context, and
# (2) cancelling this workflow will prevent triggering of any related `workflow_run` CIs, and
# (3) in the edge case wherein the `workflow_run` CI is already in progress, its results will be over-
# written by the results of the next `workflow_run` CI due to timing, so it is not a big deal. it
# is not guaranteed, however, but the risk is acceptable given the status checks are required on
# a commit hash basis. in the worst case, we will see a comment referring to the old commit hash
# via `status-comment.yml` or similar.
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref_name || github.sha }}
cancel-in-progress: true
jobs:
setup:
# A full job can be used as a reusable workflow but not a step.
uses: ./.github/workflows/reusable-foundry-setup.yml
with:
# The below line does not accept environment variables,
# so it becomes the single source of truth for the version.
foundry-version: nightly
build:
# Caching is slow; takes about 3 minutes.
timeout-minutes: 15
runs-on: ubuntu-latest
needs: setup
outputs:
# The cache-key only contains the version name. It is only used so that the name does not
# need to be repeated everywhere; instead setting the `foundry-version` above suffices.
cache-key: ${{ needs.setup.outputs.cache-key }}
# Github's cache actions are a bit weird to deal with. It wouldn't let me restore the
# binaries to /usr/bin, so I restored them to the original location and added it to PATH.
# This output will let us carry it to other jobs.
installation-dir: ${{ needs.setup.outputs.installation-dir }}
steps:
- name: Restore cached Foundry toolchain
uses: actions/cache/restore@v3
with:
path: ${{ needs.setup.outputs.installation-dir }}
key: ${{ needs.setup.outputs.cache-key }}
- name: Add Foundry to PATH
run: echo "${{ needs.setup.outputs.installation-dir }}" >> "$GITHUB_PATH"
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: recursive
- name: Build
run: forge build
- name: Cache `forge build` results
uses: actions/cache/save@v3
with:
path: |
./lib
./out
./cache
./broadcast
key: build-${{ github.event.pull_request.head.sha || github.event.after || github.sha }}
test:
# Takes less than 30s
timeout-minutes: 5
runs-on: ubuntu-latest
needs: build
steps:
- name: Restore cached Foundry toolchain
uses: actions/cache/restore@v3
with:
path: ${{ needs.build.outputs.installation-dir }}
key: ${{ needs.build.outputs.cache-key }}
- name: Add Foundry to PATH
run: echo "${{ needs.build.outputs.installation-dir }}" >> "$GITHUB_PATH"
- name: Checkout repository
uses: actions/checkout@v4
- name: Restore `forge build` results
uses: actions/cache/restore@v3
with:
path: |
./lib
./out
./cache
./broadcast
key: build-${{ github.event.pull_request.head.sha || github.event.after || github.sha }}
- name: Clear out the `etherscan` section in `foundry.toml` for missing env vars
run: sed -i '/\[etherscan\]/,/^\[/ s/^/#/' foundry.toml
- name: Run tests
env:
FOUNDRY_PROFILE: test
run: forge test
- name: Set test snapshot as summary
env:
FOUNDRY_PROFILE: test
NO_COLOR: 1
run: forge snapshot >> "$GITHUB_STEP_SUMMARY"
format:
# Takes less than 30s
timeout-minutes: 5
runs-on: ubuntu-latest
needs: build
steps:
- name: Restore cached Foundry toolchain
uses: actions/cache/restore@v3
with:
path: ${{ needs.build.outputs.installation-dir }}
key: ${{ needs.build.outputs.cache-key }}
- name: Add Foundry to PATH
run: echo "${{ needs.build.outputs.installation-dir }}" >> "$GITHUB_PATH"
- name: Checkout repository
uses: actions/checkout@v4
- name: Restore `forge build` results
uses: actions/cache/restore@v3
with:
path: |
./lib
./out
./cache
./broadcast
key: build-${{ github.event.pull_request.head.sha || github.event.after || github.sha }}
- name: Check formatting
run: forge fmt --check
check-contract-deployments:
# Takes less than 60s
timeout-minutes: 10
runs-on: ubuntu-latest
needs: build
steps:
- name: Restore cached Foundry toolchain
uses: actions/cache/restore@v3
with:
path: ${{ needs.build.outputs.installation-dir }}
key: ${{ needs.build.outputs.cache-key }}
- name: Add Foundry to PATH
run: echo "${{ needs.build.outputs.installation-dir }}" >> "$GITHUB_PATH"
- name: Checkout repository
uses: actions/checkout@v4
- name: Validate deployedContracts.json and prepare artifact
run: |
data=$(cat script/deployments/deployedContracts.json)
bootstrap=$(echo "$data" | jq -r '.clientChain.bootstrapLogic // empty')
clientGateway=$(echo "$data" | jq -r '.clientChain.clientGatewayLogic // empty')
vault=$(echo "$data" | jq -r '.clientChain.vaultImplementation // empty')
rewardVault=$(echo "$data" | jq -r '.clientChain.rewardVaultImplementation // empty')
capsule=$(echo "$data" | jq -r '.clientChain.capsuleImplementation // empty')
validate_address() {
local address=$1
if [ -z "$address" ]; then
echo "Validation failed: Address is empty"
exit 1
fi
if [ "$(cast 2a $address)" != "$address" ]; then
echo "Validation failed: $address is not a valid Ethereum checksum address"
exit 1
fi
}
# Check each address
echo "Validating bootstrap address..."
validate_address "$bootstrap"
echo "Validating clientGateway address..."
validate_address "$clientGateway"
echo "Validating vault address..."
validate_address "$vault"
echo "Validating rewardVault address..."
validate_address "$rewardVault"
echo "Validating capsule address..."
validate_address "$capsule"
# Prepare JSON for artifact. Instead of using the file within the repo,
# we create an artifact from the PR because the `compare-layouts` workflow
# runs on the base branch and doesn't have access to the PR's files.
# Given the presence of the artifact, technically, the above validation
# could be offloaded to the `compare-layouts` workflow, but this is a
# basic short circuit to avoid running the `compare-layouts` workflow
# if the PR has invalid addresses. Other validations to include, if
# possible, would be the verification of the contract on Etherscan;
# however, we cannot do that in the PR context without leaking the
# Etherscan API key.
# Note that
# (0) we use the logic addresses to match the comparison code: eg. Bootstrap is
# compared against BootstrapLogic instead of Bootstrap because Bootstrap is
# a proxy contract that points to the logic contract.
# (1) keys of the input json dict below are sourced from `deployedContracts.json`
# (2) keys of the output json dict below are case sensitive and must match the
# keys `x.deployed.json` defined in `compareLayouts.js` exactly.
jq -n \
--arg bootstrap "$bootstrapLogic" \
--arg clientGateway "$clientGatewayLogic" \
--arg vault "$vaultImplementation" \
--arg rewardVault "$rewardVaultImplementation" \
--arg capsule "$capsuleImplementation" \
'{
Bootstrap: $bootstrap,
ClientChainGateway: $clientGateway,
Vault: $vault,
RewardVault: $rewardVault,
ImuaCapsule: $capsule
}' > validatedContracts.json
echo "Validation passed: All fields are non-empty and valid Ethereum checksum addresses"
- name: Upload validated contracts artifact
uses: actions/upload-artifact@v4
with:
name: validated-contracts-${{ github.event.pull_request.head.sha || github.event.after || github.sha }}
path: validatedContracts.json
extract-storage-layout:
# Takes less than 30 seconds per matrix member
timeout-minutes: 5
runs-on: ubuntu-latest
needs: build
outputs:
storage-layout-file: ${{ steps.generate-storage-layout.outputs.output-file }}
artifact-name: ${{ steps.generate-storage-layout.outputs.artifact-name }}
strategy:
matrix:
include:
- contract: ImuachainGateway
base: true
- contract: Bootstrap
base: false
- contract: ClientChainGateway
base: false
- contract: RewardVault
base: false
- contract: Vault
base: false
- contract: ImuachainGateway
base: false
- contract: ImuaCapsule
base: false
steps:
- name: Restore cached Foundry toolchain
uses: actions/cache/restore@v3
with:
path: ${{ needs.build.outputs.installation-dir }}
key: ${{ needs.build.outputs.cache-key }}
- name: Add Foundry to PATH
run: echo "${{ needs.build.outputs.installation-dir }}" >> "$GITHUB_PATH"
- name: Checkout repository
uses: actions/checkout@v4
if: ${{ !matrix.base }}
- name: Checkout base branch of repository
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.base.ref || github.event.before }}
submodules: recursive
if: ${{ matrix.base }}
- name: Restore `forge build` results
uses: actions/cache/restore@v3
# The restoration can only happen for the non-base case. For the base case,
# the context is different and anything created within the PR context will
# not be available to the cache restore action.
if: ${{ !matrix.base }}
with:
path: |
./lib
./out
./cache
./broadcast
key: build-${{ github.event.pull_request.head.sha || github.event.after || github.sha }}
- name: Generate storage layout file
id: generate-storage-layout
run: |
set -e
artifact_name="compiled-layout-${{ matrix.contract }}"
if [ "${{ matrix.base }}" = "true" ]; then
output_file="${{ matrix.contract }}.base.json"
artifact_name="${artifact_name}-base"
else
output_file="${{ matrix.contract }}.compiled.json"
artifact_name="${artifact_name}-proposed"
fi
artifact_name="${artifact_name}-${{ github.event.pull_request.head.sha || github.event.after || github.sha }}"
forge inspect --json src/core/${{ matrix.contract }}.sol:${{ matrix.contract }} storage-layout > $output_file
echo "output-file=$output_file" >> "$GITHUB_OUTPUT"
echo "artifact-name=$artifact_name" >> "$GITHUB_OUTPUT"
- name: Upload storage layout file as an artifact
uses: actions/upload-artifact@v4
with:
path: ${{ steps.generate-storage-layout.outputs.output-file }}
name: ${{ steps.generate-storage-layout.outputs.artifact-name }}
combine-storage-layouts:
# Takes less than 10 seconds
timeout-minutes: 5
runs-on: ubuntu-latest
needs:
- extract-storage-layout
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
# No name means all artifacts created by this workflow are downloaded
# within their respective subfolders (paths) inside the provided path (`combined`).
with:
path: combined
- name: Zip up the compiled layouts
run: find combined -type f -name "*.json" ! -name "validatedContracts.json" -exec zip -j compiled-layouts.zip {} +
- name: Upload the compiled layouts file as an artifact
uses: actions/upload-artifact@v4
with:
path: compiled-layouts.zip
name: compiled-layouts-${{ github.event.pull_request.head.sha || github.event.after || github.sha }}