Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
322725a
refactor(common): align hardhat task arguments and definitions
isaacdecoded Mar 24, 2026
2ea1e56
test(gateway-contracts): refactor variable declaration into scoped bl…
isaacdecoded Mar 23, 2026
eff4b2d
chore(common): introduce integrity check for contract licenses
isaacdecoded Mar 23, 2026
9aa22e0
refactor(gateway-contracts): improve pause all contracts method behavior
isaacdecoded Jan 8, 2026
7923cd3
chore(gateway-contracts): refresh bindings and selectors
isaacdecoded Jan 8, 2026
ed0f3da
refactor(common): align missed tasks
isaacdecoded Mar 25, 2026
5a67573
refactor(gateway-contracts): extend the no-global vars pattern
isaacdecoded Mar 25, 2026
ae20591
Update ci/check_spdx_licenses.sh
isaacdecoded Mar 25, 2026
44205ad
Update gateway-contracts/contracts/GatewayConfig.sol
isaacdecoded Mar 25, 2026
f010afa
refactor(gateway-contracts): use stored local variables to avoid mult…
isaacdecoded Mar 25, 2026
57baf54
chore(gateway-contracts): refresh rust bindings
isaacdecoded Mar 25, 2026
c1bf4db
ci(common): include library solidity and host library in the spdx lic…
isaacdecoded Mar 25, 2026
c6811bd
feat(ci): add QA-facing upgrade report
Eikix Mar 23, 2026
1f72238
fix(ci): install soldeer deps in upgrade report
Eikix Mar 24, 2026
939bb6d
fix(test-suite): copro sha1 for fhevm-cli
rudy-6-4 Mar 26, 2026
4b627f2
Merge of #2157
mergify[bot] Mar 26, 2026
fa1474a
Merge of #2163
mergify[bot] Mar 26, 2026
3a398c3
Merge of #2158
mergify[bot] Mar 26, 2026
40e25e7
Merge of #1747
mergify[bot] Mar 26, 2026
295c351
Merge of #2178
mergify[bot] Mar 26, 2026
4f0f225
Merge of #2154
mergify[bot] Mar 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/contracts-upgrade-version-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,13 @@ jobs:
- .github/workflows/contracts-upgrade-version-check.yml
- ci/check-upgrade-versions.ts
- ci/merge-address-constants.ts
- ci/upgrade-version-check-lib.ts
- host-contracts/**
gateway-contracts:
- .github/workflows/contracts-upgrade-version-check.yml
- ci/check-upgrade-versions.ts
- ci/merge-address-constants.ts
- ci/upgrade-version-check-lib.ts
- gateway-contracts/**

check:
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/gateway-contracts-integrity-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ jobs:
gw-contracts:
- .github/workflows/gateway-contracts-integrity-checks.yml
- gateway-contracts/**
- ci/check_spdx_licenses.sh
- ci/contracts_bindings_update.py
contract-integrity-checks:
name: gateway-contracts-integrity-checks/contract-integrity-checks (bpr)
needs: check-changes
Expand Down Expand Up @@ -72,6 +74,10 @@ jobs:
working-directory: gateway-contracts
run: make check-mocks

- name: Check SPDX license headers
working-directory: gateway-contracts
run: make check-spdx-headers

- name: Check licenses compliance
working-directory: gateway-contracts
run: make check-licenses
6 changes: 6 additions & 0 deletions .github/workflows/host-contracts-integrity-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ jobs:
host-contracts:
- .github/workflows/host-contracts-integrity-checks.yml
- host-contracts/**
- ci/check_spdx_licenses.sh
- ci/contracts_bindings_update.py
contract-integrity-checks:
name: host-contracts-integrity-checks/contract-integrity-checks (bpr)
Expand Down Expand Up @@ -68,3 +70,7 @@ jobs:
- name: Check contract selectors are up-to-date
working-directory: host-contracts
run: make check-selectors

- name: Check SPDX license headers
working-directory: host-contracts
run: make check-spdx-headers
50 changes: 50 additions & 0 deletions .github/workflows/library-solidity-integrity-checks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# This workflow verifies that:
# - Dependency licenses compliance
name: library-solidity-integrity-checks

on:
pull_request:

permissions: {}

concurrency:
group: library-solidity-integrity-checks-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}

jobs:
check-changes:
name: library-solidity-integrity-checks/check-changes
permissions:
contents: 'read' # Required to checkout repository code
runs-on: ubuntu-latest
outputs:
changes-library-solidity: ${{ steps.filter.outputs.library-solidity }}
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: 'false'
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: filter
with:
filters: |
library-solidity:
- .github/workflows/library-solidity-integrity-checks.yml
- library-solidity/**
- ci/check_spdx_licenses.sh
contract-integrity-checks:
name: library-solidity-integrity-checks/contract-integrity-checks (bpr)
needs: check-changes
if: ${{ needs.check-changes.outputs.changes-library-solidity == 'true' }}
permissions:
contents: 'read' # Required to checkout repository code
runs-on: ubuntu-latest
steps:
- name: Checkout project
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: 'false'

- name: Check SPDX license headers
working-directory: library-solidity
run: make check-spdx-headers
125 changes: 11 additions & 114 deletions ci/check-upgrade-versions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,136 +2,33 @@
// Checks that upgradeable contracts have proper version bumps when bytecode changes.
// Usage: bun ci/check-upgrade-versions.ts <baseline-pkg-dir> <pr-pkg-dir>

import { readFileSync, existsSync } from "fs";
import { execSync } from "child_process";
import { join } from "path";
import { collectUpgradeVersionResults } from "./upgrade-version-check-lib";

const [baselineDir, prDir] = process.argv.slice(2);
if (!baselineDir || !prDir) {
console.error("Usage: bun ci/check-upgrade-versions.ts <baseline-pkg-dir> <pr-pkg-dir>");
process.exit(1);
}

const manifestPath = join(prDir, "upgrade-manifest.json");
if (!existsSync(manifestPath)) {
console.error(`::error::upgrade-manifest.json not found in ${prDir}`);
process.exit(1);
}

const VERSION_RE = /(?<name>REINITIALIZER_VERSION|MAJOR_VERSION|MINOR_VERSION|PATCH_VERSION)\s*=\s*(?<value>\d+)/g;

function extractVersions(filePath: string) {
const source = readFileSync(filePath, "utf-8");
const versions: Record<string, number> = {};
for (const { groups } of source.matchAll(VERSION_RE)) {
versions[groups!.name] = Number(groups!.value);
}
return { versions, source };
}

function forgeInspect(contract: string, root: string): string | null {
try {
const raw = execSync(`forge inspect "contracts/${contract}.sol:${contract}" --root "${root}" deployedBytecode`, {
encoding: "utf-8",
stdio: ["pipe", "pipe", "pipe"],
env: { ...process.env, NO_COLOR: "1" },
});
// Extract hex bytecode — forge may prepend ANSI codes or compilation progress to stdout
const match = raw.match(/0x[0-9a-fA-F]+/);
return match ? match[0] : null;
} catch (e: any) {
if (e.stderr) console.error(String(e.stderr));
return null;
}
}

const contracts: string[] = JSON.parse(readFileSync(manifestPath, "utf-8"));
const results = collectUpgradeVersionResults(baselineDir, prDir);
let errors = 0;

for (const name of contracts) {
console.log(`::group::Checking ${name}`);
for (const result of results) {
console.log(`::group::Checking ${result.name}`);
try {
const baseSol = join(baselineDir, "contracts", `${name}.sol`);
const prSol = join(prDir, "contracts", `${name}.sol`);

if (!existsSync(baseSol)) {
console.log(`Skipping ${name} (new contract, not in baseline)`);
continue;
}

if (!existsSync(prSol)) {
console.error(`::error::${name} listed in upgrade-manifest.json but missing in PR`);
errors++;
if (!result.baselineExists) {
console.log(`Skipping ${result.name} (new contract, not in baseline)`);
continue;
}

const { versions: baseV } = extractVersions(baseSol);
const { versions: prV, source: prSrc } = extractVersions(prSol);

let parseFailed = false;
for (const key of ["REINITIALIZER_VERSION", "MAJOR_VERSION", "MINOR_VERSION", "PATCH_VERSION"]) {
if (baseV[key] == null || prV[key] == null) {
console.error(`::error::Failed to parse ${key} for ${name}`);
errors++;
parseFailed = true;
}
}
if (parseFailed) continue;

const prBytecode = forgeInspect(name, prDir);
if (prBytecode == null) {
console.error(`::error::Failed to compile ${name} on PR`);
errors++;
continue;
}

const baseBytecode = forgeInspect(name, baselineDir);
if (baseBytecode == null) {
console.error(`::error::Failed to compile ${name} on baseline`);
errors++;
continue;
}
const bytecodeChanged = baseBytecode !== prBytecode;
const reinitChanged = baseV.REINITIALIZER_VERSION !== prV.REINITIALIZER_VERSION;
const versionChanged =
baseV.MAJOR_VERSION !== prV.MAJOR_VERSION ||
baseV.MINOR_VERSION !== prV.MINOR_VERSION ||
baseV.PATCH_VERSION !== prV.PATCH_VERSION;

if (!bytecodeChanged) {
console.log(`${name}: bytecode unchanged`);
if (reinitChanged) {
console.error(
`::error::${name} REINITIALIZER_VERSION bumped (${baseV.REINITIALIZER_VERSION} -> ${prV.REINITIALIZER_VERSION}) but bytecode is unchanged`,
);
errors++;
}
continue;
}

console.log(`${name}: bytecode CHANGED`);

if (!reinitChanged) {
console.error(
`::error::${name} bytecode changed but REINITIALIZER_VERSION was not bumped (still ${prV.REINITIALIZER_VERSION})`,
);
errors++;
if (result.bytecodeChanged) {
console.log(`${result.name}: bytecode CHANGED`);
} else {
// Convention: reinitializeV{N-1} for REINITIALIZER_VERSION=N
const expectedFn = `reinitializeV${prV.REINITIALIZER_VERSION - 1}`;
const uncommented = prSrc.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*$/gm, "");
if (!new RegExp(`function\\s+${expectedFn}\\s*\\(`).test(uncommented)) {
console.error(
`::error::${name} has REINITIALIZER_VERSION=${prV.REINITIALIZER_VERSION} but no ${expectedFn}() function found`,
);
errors++;
}
console.log(`${result.name}: bytecode unchanged`);
}

if (!versionChanged) {
console.error(
`::error::${name} bytecode changed but semantic version was not bumped (still v${prV.MAJOR_VERSION}.${prV.MINOR_VERSION}.${prV.PATCH_VERSION})`,
);
for (const error of result.errors) {
console.error(`::error::${error}`);
errors++;
}
} finally {
Expand Down
58 changes: 58 additions & 0 deletions ci/check_spdx_licenses.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#!/usr/bin/env bash
# Check that all Solidity contracts use the expected SPDX license identifier.

set -euo pipefail

EXPECTED_LICENSE="BSD-3-Clause-Clear"
EXIT_CODE=0
DIRS=()
EXCLUDES=()

# Parse arguments
while [[ $# -gt 0 ]]; do
case "$1" in
--exclude)
EXCLUDES+=("$2")
shift 2
;;
*)
DIRS+=("$1")
shift
;;
esac
done

# Default to contracts/ if no directories specified
if [[ ${#DIRS[@]} -eq 0 ]]; then
DIRS=("contracts")
fi

for dir in "${DIRS[@]}"; do
while IFS= read -r -d '' file; do
# Check if file matches any exclude pattern
skip=false
for exclude in ${EXCLUDES[@]+"${EXCLUDES[@]}"}; do
if [[ "$file" == *"$exclude"* ]]; then
skip=true
break
fi
done
if "$skip"; then
continue
fi

first_line=$(head -n 1 "$file")
if [[ "$first_line" != "// SPDX-License-Identifier: ${EXPECTED_LICENSE}" ]]; then
echo "ERROR: Wrong or missing license in $file"
echo " Found: $first_line"
echo " Expected: // SPDX-License-Identifier: ${EXPECTED_LICENSE}"
EXIT_CODE=1
fi
done < <(find "$dir" -name '*.sol' -print0 | sort -z)
done

if [ "$EXIT_CODE" -eq 0 ]; then
echo "All Solidity files use SPDX-License-Identifier: ${EXPECTED_LICENSE}"
fi

exit "$EXIT_CODE"
Loading
Loading