Skip to content

Commit

Permalink
feat(ci): add forge fmt and solhint jobs (#17)
Browse files Browse the repository at this point in the history
* chore(build): add prettier and solidity plugin

* chore(build): add `lint.yml` workflow

* chore(lint): add prettier config

* chore(lint): apply lint

* chore(lint): apply lint on missed file

* chore(ci): change trigger for lint ci

It does not need to trigger on each push

* chore(lint): add solidity parser to prettierrc

* doc(bootstrap): remove superfluous comments

* doc(test): remove unnecessary comments

* refactor: implement token whitelisting in storage

This way, we avoid repeating the token whitelisting code in `Bootstrap`
and `ClientChainGateway`.

* chore(lint)

* fix(test): update test strings in Bootstrap

* chore(lint)

* Revert chore(build): add prettier solidity plugin

This reverts commit 9a4f47b.

* chore(build): remove prettier

* fix(build): move to `forge fmt` from prettier

* fix(ci): update test comment

* chore(lint): apply `forge fmt`

It applies recursively automatically

* fix(ci): fail if not formatted

* chore(lint): set up solhint config

* build(ci): set up `solhint` workflow

* chore(lint): run `solhint`

* chore(fmt): run `forge fmt`

* fix(bootstrap): deploy vaults correctly

I had mistakenly confused the `BeaconProxyBytecode` and the beacon chain
related functions

* fix(build): rename fmt workflow

* fix(ci): rename `lint` workflow

* fix(bootstrap): validate client chain init params

* fix(mocks): return value in withdraw mock

* test(doc): add comments for Bootstrap deposit test

* fix(bootstrap): validate length of init data >= 4

* doc(test): update bootstrap unit test comments

* chore(ci): forge fmt

* chore(fmt): bring back Endian.sol and add config

* build(ci): merge workflows and use cache

We now have a multi-job workflow, which means it will run the jobs in
parallel. Between jobs, we cache the artifacts generated by Foundry so
they can be reused. The artifacts cached are the result of compilation
by Foundry, and hence, they can be reused across jobs. The `build` job
is responsible for generating them, while the `test` and `fmt` jobs can
reuse them, which is why they `need` the `build` job.

* build(ci): use a common foundry-setup action

...and do not let the cache key depend on the job name.

* build(ci): another attempt at common workflow

* fix(ci): correct extension of foundry-setup

* build(ci): another attempt

* fix(ci): save key cache correctly

* fix(ci): remove deprecated code

* fix(ci): use output instead of env

* fix(ci): save install dir for forge

* fix(ci): finally, fix the workflows

* fix(git): ignore the forge snapshot

* fix(ci): also cache git submodules

* chore(lint): lint the ci

* refactor: getWhitelistedTokensCount in gateway

* config: activate new Foundry rules

* chore(fmt): run `forge fmt`

* lint:Update src/core/ExocoreGateway.sol

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* refactor(bootstrap): use modifier not require

* lint: use disable-next-item for clarity

...instead of ignoring the whole file

* optimize: explicitly mark recipient as payable

* chore(lint): run forge fmt

---------

Co-authored-by: adu <[email protected]>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
  • Loading branch information
3 people authored Jun 5, 2024
1 parent e57bf41 commit 8c0aef0
Show file tree
Hide file tree
Showing 95 changed files with 2,223 additions and 2,003 deletions.
132 changes: 132 additions & 0 deletions .github/workflows/forge-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
---
name: Forge CI to build, test and format

on:
pull_request:
push:
branches:
- main
- release/**
tags:
- "*"

jobs:
setup:
uses: ./.github/workflows/foundry-setup.yml
with:
foundry-version: nightly-f625d0fa7c51e65b4bf1e8f7931cd1c6e2e285e9

build:
runs-on: ubuntu-latest
needs: setup
outputs:
installation-dir: ${{ needs.setup.outputs.installation-dir }}
cache-key: ${{ needs.setup.outputs.cache-key }}
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- 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: Build
run: forge build
- name: Add comment for build failure
if: failure()
uses: actions/github-script@v6
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: 'The build has failed. Please check the logs.'
})
- name: Cache build artifacts
uses: actions/cache/save@v3
with:
path: |
./lib
./out
./cache
./broadcast
key: ${{ runner.os }}-build-${{ github.sha }}

test:
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v4
- 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: Restore build artifacts
uses: actions/cache/restore@v3
with:
path: |
./lib
./out
./cache
./broadcast
key: ${{ runner.os }}-build-${{ github.sha }}
- name: Run tests
run: forge test -vvv
- name: Run test snapshot
run: NO_COLOR=1 forge snapshot >> $GITHUB_STEP_SUMMARY
- name: Add comment for test failure
if: failure()
uses: actions/github-script@v6
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: 'The tests have failed. Please check the logs.'
})
fmt:
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v4
- 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: Restore build artifacts
uses: actions/cache/restore@v3
with:
path: |
./lib
./out
./cache
./broadcast
key: ${{ runner.os }}-build-${{ github.sha }}
- name: Check formatting
run: forge fmt --check
- name: Add comment for format failure
if: failure()
uses: actions/github-script@v6
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: 'The code is not formatted correctly. Please run `forge fmt` and push the changes.'
})
47 changes: 47 additions & 0 deletions .github/workflows/foundry-setup.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
name: Foundry Setup

on:
workflow_call:
inputs:
foundry-version:
required: true
type: string
outputs:
installation-dir:
description: "The installation directory of Foundry toolchain"
value: ${{ jobs.setup.outputs.installation-dir }}
cache-key:
description: "The cache key for Foundry toolchain"
value: ${{ jobs.setup.outputs.cache-key }}

jobs:
setup:
runs-on: ubuntu-latest
outputs:
cache-key: ${{ steps.set-cache-key.outputs.cache-key }}
installation-dir: ${{ steps.find-path.outputs.installation-dir }}
steps:
- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
with:
version: ${{ inputs.foundry-version }}
- name: Print forge version
run: forge --version
# Unfortunately, the `foundry-toolchain` action installs it in a
# randomly generated location, so we must determine it ourselves
- name: Determine Foundry installation path
id: find-path
run: |
installation_path=$(which forge)
installation_dir=$(dirname $installation_path)
echo "installation-dir=$installation_dir" >> "$GITHUB_OUTPUT"
- name: Cached Foundry toolchain
uses: actions/cache/save@v3
with:
path: ${{ steps.find-path.outputs.installation-dir }}
key: ${{ runner.os }}-foundry-${{ inputs.foundry-version }}
- name: Set cache key
id: set-cache-key
run: |
echo "cache-key=${{ runner.os }}-foundry-${{ inputs.foundry-version }}" >> "$GITHUB_OUTPUT"
45 changes: 45 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Run `solhint` linter

on:
pull_request:
push:
branches:
- main
- release/**
tags:
- "*"

jobs:
check:
strategy:
fail-fast: true

name: Foundry project
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v2
with:
node-version: '22'

- name: Install Solhint
run: npm install --save-dev solhint

- name: Run Solhint
run: |
npx solhint 'src/**/*.sol' -c ./src/.solhint.json
- name: Add comment on failure
if: failure()
uses: actions/github-script@v6
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: 'Linting failed. Please check the logs.'
})
56 changes: 0 additions & 56 deletions .github/workflows/test.yml

This file was deleted.

2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,5 @@ node_modules
**/cache_hardhat

.idea

.gas-snapshot
1 change: 1 addition & 0 deletions .solhintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
src/lzApp/*.sol
8 changes: 7 additions & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,11 @@ evm_version = "paris"
[rpc_endpoints]
ethereum_local_rpc = "${ETHEREUM_LOCAL_RPC}"
exocore_local_rpc = "${EXOCORE_LOCAL_RPC}"
# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options

[fmt]
number_underscore = "thousands"
sort_imports = true
wrap_comments = true
single_line_statement_blocks = "multi"
contract_new_lines = true
# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options
16 changes: 8 additions & 8 deletions script/10_DeployExocoreGatewayOnly.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ pragma solidity ^0.8.19;
import {ILayerZeroEndpointV2} from "@layerzero-v2/protocol/contracts/interfaces/ILayerZeroEndpointV2.sol";

import {ProxyAdmin} from "@openzeppelin-contracts/contracts/proxy/transparent/ProxyAdmin.sol";
import {TransparentUpgradeableProxy} from "@openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import {TransparentUpgradeableProxy} from
"@openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";

import {ExocoreGateway} from "../src/core/ExocoreGateway.sol";
import "forge-std/Script.sol";

import {BaseScript} from "./BaseScript.sol";
import "forge-std/Script.sol";

contract DeployExocoreGatewayOnly is BaseScript {

Expand Down Expand Up @@ -35,8 +37,7 @@ contract DeployExocoreGatewayOnly is BaseScript {
address(exocoreGatewayLogic),
address(exocoreProxyAdmin),
abi.encodeWithSelector(
exocoreGatewayLogic.initialize.selector,
payable(exocoreValidatorSet.addr)
exocoreGatewayLogic.initialize.selector, payable(exocoreValidatorSet.addr)
)
)
)
Expand All @@ -52,10 +53,9 @@ contract DeployExocoreGatewayOnly is BaseScript {
vm.serializeAddress(exocoreContracts, "exocoreGateway", address(exocoreGateway));

string memory deployedContracts = "deployedContracts";
string memory finalJson =
vm.serializeString(deployedContracts, "exocore", exocoreContractsOutput);
string memory finalJson = vm.serializeString(deployedContracts, "exocore", exocoreContractsOutput);

vm.writeJson(finalJson, "script/deployedExocoreGatewayOnly.json");

}
}

}
13 changes: 7 additions & 6 deletions script/11_SetPeers.s.sol
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
pragma solidity ^0.8.19;

import {ExocoreGateway} from "../src/core/ExocoreGateway.sol";
import {Bootstrap} from "../src/core/Bootstrap.sol";
import {ExocoreGateway} from "../src/core/ExocoreGateway.sol";

import {CLIENT_CHAINS_PRECOMPILE_ADDRESS} from "../src/interfaces/precompiles/IClientChains.sol";

import "forge-std/Script.sol";
import {BaseScript} from "./BaseScript.sol";
import "forge-std/Script.sol";

import "@layerzero-v2/protocol/contracts/libs/AddressCast.sol";

contract SetPeersAndUpgrade is BaseScript {

using AddressCast for address;

address bootstrapAddr;
Expand Down Expand Up @@ -50,8 +51,7 @@ contract SetPeersAndUpgrade is BaseScript {
uint256 i = 0;
uint256 tries = 5;
bool success;
while(i < tries) {

while (i < tries) {
vm.selectFork(exocore);
success = gateway.peers(clientChainId) == bootstrapAddr.toBytes32();

Expand Down Expand Up @@ -90,8 +90,9 @@ contract SetPeersAndUpgrade is BaseScript {
console.log(
"source .env && cast send --rpc-url $EXOCORE_TESETNET_RPC",
exocoreGatewayAddr,
"\"markBootstrapOnAllChains()\"",
'"markBootstrapOnAllChains()"',
"--private-key $TEST_ACCOUNT_THREE_PRIVATE_KEY"
);
}
}

}
Loading

0 comments on commit 8c0aef0

Please sign in to comment.