From 1763818ff2ded6f76668c20be8f4f0fee6d9dd97 Mon Sep 17 00:00:00 2001 From: elle-j Date: Wed, 29 Apr 2026 13:24:39 +0200 Subject: [PATCH 01/20] Add simple foundry project. --- tooling-projects/foundry/counter/foundry.toml | 22 +++++++++++++++++ .../foundry/counter/src/Counter.sol | 14 +++++++++++ .../foundry/counter/test/Counter.t.sol | 24 +++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 tooling-projects/foundry/counter/foundry.toml create mode 100644 tooling-projects/foundry/counter/src/Counter.sol create mode 100644 tooling-projects/foundry/counter/test/Counter.t.sol diff --git a/tooling-projects/foundry/counter/foundry.toml b/tooling-projects/foundry/counter/foundry.toml new file mode 100644 index 00000000..9f907d62 --- /dev/null +++ b/tooling-projects/foundry/counter/foundry.toml @@ -0,0 +1,22 @@ +[profile.default] +src = "src" +test = "test" +libs = ["lib"] +solc = "0.8.34" +remappings = ["forge-std/=lib/forge-std/src/"] +extra_output = [ + "abi", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "ir", + "irOptimized", + "evm.bytecode", + "evm.deployedBytecode", + "evm.assembly", + "evm.methodIdentifiers", +] + +[profile.default.polkadot] +resolc_compile = true diff --git a/tooling-projects/foundry/counter/src/Counter.sol b/tooling-projects/foundry/counter/src/Counter.sol new file mode 100644 index 00000000..aded7997 --- /dev/null +++ b/tooling-projects/foundry/counter/src/Counter.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +contract Counter { + uint256 public number; + + function setNumber(uint256 newNumber) public { + number = newNumber; + } + + function increment() public { + number++; + } +} diff --git a/tooling-projects/foundry/counter/test/Counter.t.sol b/tooling-projects/foundry/counter/test/Counter.t.sol new file mode 100644 index 00000000..48319108 --- /dev/null +++ b/tooling-projects/foundry/counter/test/Counter.t.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +import {Test} from "forge-std/Test.sol"; +import {Counter} from "../src/Counter.sol"; + +contract CounterTest is Test { + Counter public counter; + + function setUp() public { + counter = new Counter(); + counter.setNumber(0); + } + + function test_Increment() public { + counter.increment(); + assertEq(counter.number(), 1); + } + + function testFuzz_SetNumber(uint256 x) public { + counter.setNumber(x); + assertEq(counter.number(), x); + } +} From 5685cd9b2368b5c6ec21bee02398f54ab50efc0c Mon Sep 17 00:00:00 2001 From: elle-j Date: Wed, 29 Apr 2026 13:31:00 +0200 Subject: [PATCH 02/20] Add CI workflow using foundry. --- .github/workflows/foundry.yml | 103 ++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 .github/workflows/foundry.yml diff --git a/.github/workflows/foundry.yml b/.github/workflows/foundry.yml new file mode 100644 index 00000000..1c4e8d16 --- /dev/null +++ b/.github/workflows/foundry.yml @@ -0,0 +1,103 @@ +name: Foundry Integration + +on: + push: + branches: ["main"] + paths-ignore: + - "**.md" + pull_request: + branches: ["main"] + types: [opened, synchronize] + paths-ignore: + - "**.md" + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +env: + CARGO_TERM_COLOR: always + # Workflow-internal foundry envs are prefixed with `CI_` to not conflict with the + # `FOUNDRY_*` namespace, which foundry itself will interpret for its configuration. + CI_FOUNDRY_PROJECT_ROOT: tooling-projects/foundry/counter + # This is currently the commit that adds support for resolc ">=0.6.0, <2.0.0". + # The latest release as of Apr. 28, 2026 supports ">=0.6.0, <0.7.0". + # Once a release includes the updated supported versions, this can be changed to a + # tag in order to download the prebuilt binary. + CI_FOUNDRY_POLKADOT_COMMIT: b3173d0584382687cc96b2af072d8cb2addf23d3 + +jobs: + use-foundry: + runs-on: ubuntu-24.04 + steps: + - name: Checkout revive + uses: actions/checkout@v4 + + - name: Set Up Rust Toolchain + uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + # without this it will override our rust flags + rustflags: "" + + - name: Download LLVM + uses: ./.github/actions/get-llvm + with: + target: x86_64-unknown-linux-gnu + + - name: Set LLVM Environment Variables + run: echo "LLVM_SYS_221_PREFIX=$(pwd)/llvm-x86_64-unknown-linux-gnu" >> $GITHUB_ENV + + - name: Build resolc + run: | + make install-bin + echo "RESOLC_BIN=$GITHUB_WORKSPACE/target/release/resolc" >> "$GITHUB_ENV" + + # TODO: Remove once the next step replaces `--commit` with `--install`. + - name: Cache foundryup-polkadot + uses: actions/cache@v5 + with: + path: ~/.foundry + key: foundryup-polkadot-${{ env.CI_FOUNDRY_POLKADOT_COMMIT }} + + - name: Install foundryup-polkadot and forge + run: | + # TODO: Remove "--branch lj/fix-foundryup-script" once this is merged: https://github.com/paritytech/foundry-polkadot/pull/555 + # TODO: Replace "--commit" with "--install" once a release with this commit exists: https://github.com/paritytech/foundry-polkadot/commit/b3173d0584382687cc96b2af072d8cb2addf23d3 + + curl -fsSL https://raw.githubusercontent.com/paritytech/foundry-polkadot/refs/heads/master/foundryup/install | bash + "$HOME/.foundry/bin/foundryup-polkadot" \ + --branch lj/fix-foundryup-script \ + --commit "$CI_FOUNDRY_POLKADOT_COMMIT" + echo "$HOME/.foundry/bin" >> "$GITHUB_PATH" + + - name: Check Tool Versions + run: | + foundryup-polkadot --version + forge --version + + - name: Fetch Project Dependencies + run: | + mkdir -p "$CI_FOUNDRY_PROJECT_ROOT/lib" + git clone --depth 1 --branch v1.15.0 \ + https://github.com/foundry-rs/forge-std.git "$CI_FOUNDRY_PROJECT_ROOT/lib/forge-std" + + - name: Build Project + run: forge build --root "$CI_FOUNDRY_PROJECT_ROOT" --use-resolc "$RESOLC_BIN" + + - name: Verify Output + run: | + cd "$CI_FOUNDRY_PROJECT_ROOT" + forge inspect Counter bytecode | grep -q '^0x50564d' + forge inspect Counter deployedBytecode | grep -q '^0x50564d' + forge inspect Counter irOptimized | grep -q . + forge inspect Counter ir | grep -q . + forge inspect Counter assembly | grep -q . + forge inspect Counter abi --json | jq -e 'length > 0' > /dev/null + forge inspect Counter methodIdentifiers --json | jq -e 'length > 0' > /dev/null + forge inspect Counter storageLayout --json | jq -e '.storage | length > 0' > /dev/null + forge inspect Counter metadata --json | jq -e 'length > 0' > /dev/null + forge inspect Counter devdoc --json | jq -e 'length > 0' > /dev/null + forge inspect Counter userdoc --json | jq -e 'length > 0' > /dev/null + + - name: Test project + run: forge test --root "$CI_FOUNDRY_PROJECT_ROOT" --polkadot=pvm --use-resolc "$RESOLC_BIN" -vvvv From 8e1efdac31bddd5606bb8f400f4d4866a6f9871c Mon Sep 17 00:00:00 2001 From: elle-j Date: Wed, 29 Apr 2026 13:40:21 +0200 Subject: [PATCH 03/20] Remove foundryup script workaround since a fix has been merged. --- .github/workflows/foundry.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/foundry.yml b/.github/workflows/foundry.yml index 1c4e8d16..c8a544f3 100644 --- a/.github/workflows/foundry.yml +++ b/.github/workflows/foundry.yml @@ -61,13 +61,10 @@ jobs: - name: Install foundryup-polkadot and forge run: | - # TODO: Remove "--branch lj/fix-foundryup-script" once this is merged: https://github.com/paritytech/foundry-polkadot/pull/555 # TODO: Replace "--commit" with "--install" once a release with this commit exists: https://github.com/paritytech/foundry-polkadot/commit/b3173d0584382687cc96b2af072d8cb2addf23d3 curl -fsSL https://raw.githubusercontent.com/paritytech/foundry-polkadot/refs/heads/master/foundryup/install | bash - "$HOME/.foundry/bin/foundryup-polkadot" \ - --branch lj/fix-foundryup-script \ - --commit "$CI_FOUNDRY_POLKADOT_COMMIT" + "$HOME/.foundry/bin/foundryup-polkadot" --commit "$CI_FOUNDRY_POLKADOT_COMMIT" echo "$HOME/.foundry/bin" >> "$GITHUB_PATH" - name: Check Tool Versions From 4bb3d1b02293726ac82ca136e39573bce023e954 Mon Sep 17 00:00:00 2001 From: elle-j Date: Wed, 29 Apr 2026 14:06:36 +0200 Subject: [PATCH 04/20] Fix caching. --- .github/workflows/foundry.yml | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/.github/workflows/foundry.yml b/.github/workflows/foundry.yml index c8a544f3..a01143f5 100644 --- a/.github/workflows/foundry.yml +++ b/.github/workflows/foundry.yml @@ -52,20 +52,24 @@ jobs: make install-bin echo "RESOLC_BIN=$GITHUB_WORKSPACE/target/release/resolc" >> "$GITHUB_ENV" - # TODO: Remove once the next step replaces `--commit` with `--install`. - - name: Cache foundryup-polkadot + # TODO: Could be removed once the next step replaces `--commit` with `--install`. + - name: Cache Foundry + id: cache-foundry uses: actions/cache@v5 with: path: ~/.foundry - key: foundryup-polkadot-${{ env.CI_FOUNDRY_POLKADOT_COMMIT }} + key: foundry-polkadot-${{ env.CI_FOUNDRY_POLKADOT_COMMIT }} - - name: Install foundryup-polkadot and forge + - name: Install foundryup-polkadot and the Foundry Toolchain + if: ${{ steps.cache-foundry.outputs.cache-hit != 'true' }} run: | # TODO: Replace "--commit" with "--install" once a release with this commit exists: https://github.com/paritytech/foundry-polkadot/commit/b3173d0584382687cc96b2af072d8cb2addf23d3 curl -fsSL https://raw.githubusercontent.com/paritytech/foundry-polkadot/refs/heads/master/foundryup/install | bash "$HOME/.foundry/bin/foundryup-polkadot" --commit "$CI_FOUNDRY_POLKADOT_COMMIT" - echo "$HOME/.foundry/bin" >> "$GITHUB_PATH" + + - name: Add Foundry to PATH + run: echo "$HOME/.foundry/bin" >> "$GITHUB_PATH" - name: Check Tool Versions run: | @@ -96,5 +100,5 @@ jobs: forge inspect Counter devdoc --json | jq -e 'length > 0' > /dev/null forge inspect Counter userdoc --json | jq -e 'length > 0' > /dev/null - - name: Test project + - name: Test Project run: forge test --root "$CI_FOUNDRY_PROJECT_ROOT" --polkadot=pvm --use-resolc "$RESOLC_BIN" -vvvv From e633a231c411b752548bf1f667bed94d54971731 Mon Sep 17 00:00:00 2001 From: elle-j Date: Wed, 29 Apr 2026 14:24:32 +0200 Subject: [PATCH 05/20] Add explicit optimization settings. --- .github/workflows/foundry.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/foundry.yml b/.github/workflows/foundry.yml index a01143f5..630a317b 100644 --- a/.github/workflows/foundry.yml +++ b/.github/workflows/foundry.yml @@ -83,7 +83,7 @@ jobs: https://github.com/foundry-rs/forge-std.git "$CI_FOUNDRY_PROJECT_ROOT/lib/forge-std" - name: Build Project - run: forge build --root "$CI_FOUNDRY_PROJECT_ROOT" --use-resolc "$RESOLC_BIN" + run: forge build --root "$CI_FOUNDRY_PROJECT_ROOT" --use-resolc "$RESOLC_BIN" --optimize -Oz - name: Verify Output run: | @@ -101,4 +101,4 @@ jobs: forge inspect Counter userdoc --json | jq -e 'length > 0' > /dev/null - name: Test Project - run: forge test --root "$CI_FOUNDRY_PROJECT_ROOT" --polkadot=pvm --use-resolc "$RESOLC_BIN" -vvvv + run: forge test --root "$CI_FOUNDRY_PROJECT_ROOT" --polkadot=pvm --use-resolc "$RESOLC_BIN" --optimize -Oz -vvvv From f2abd880598e2912a23b047e85965bcb9693f6b3 Mon Sep 17 00:00:00 2001 From: elle-j Date: Wed, 29 Apr 2026 15:52:16 +0200 Subject: [PATCH 06/20] Fix install path. --- .github/workflows/foundry.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/foundry.yml b/.github/workflows/foundry.yml index 630a317b..2b2f15b5 100644 --- a/.github/workflows/foundry.yml +++ b/.github/workflows/foundry.yml @@ -50,7 +50,7 @@ jobs: - name: Build resolc run: | make install-bin - echo "RESOLC_BIN=$GITHUB_WORKSPACE/target/release/resolc" >> "$GITHUB_ENV" + echo "RESOLC_BIN=$(pwd)/target/release/resolc" >> "$GITHUB_ENV" # TODO: Could be removed once the next step replaces `--commit` with `--install`. - name: Cache Foundry @@ -63,10 +63,12 @@ jobs: - name: Install foundryup-polkadot and the Foundry Toolchain if: ${{ steps.cache-foundry.outputs.cache-hit != 'true' }} run: | - # TODO: Replace "--commit" with "--install" once a release with this commit exists: https://github.com/paritytech/foundry-polkadot/commit/b3173d0584382687cc96b2af072d8cb2addf23d3 + # TODO: Replace `--commit` with `--install` once a release with this commit exists: https://github.com/paritytech/foundry-polkadot/commit/b3173d0584382687cc96b2af072d8cb2addf23d3 + # Pin install path with `FOUNDRY_DIR` to prevent the pre-existing `XDG_CONFIG_HOME` from being used. + export FOUNDRY_DIR="$HOME/.foundry" curl -fsSL https://raw.githubusercontent.com/paritytech/foundry-polkadot/refs/heads/master/foundryup/install | bash - "$HOME/.foundry/bin/foundryup-polkadot" --commit "$CI_FOUNDRY_POLKADOT_COMMIT" + "$FOUNDRY_DIR/bin/foundryup-polkadot" --commit "$CI_FOUNDRY_POLKADOT_COMMIT" - name: Add Foundry to PATH run: echo "$HOME/.foundry/bin" >> "$GITHUB_PATH" From 04e18a8a0d2f8b6c5903189a3d50728bfdb054ab Mon Sep 17 00:00:00 2001 From: elle-j Date: Wed, 29 Apr 2026 16:33:32 +0200 Subject: [PATCH 07/20] Fix build dependencies. --- .github/workflows/foundry.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/foundry.yml b/.github/workflows/foundry.yml index 2b2f15b5..2cf40a3f 100644 --- a/.github/workflows/foundry.yml +++ b/.github/workflows/foundry.yml @@ -52,7 +52,7 @@ jobs: make install-bin echo "RESOLC_BIN=$(pwd)/target/release/resolc" >> "$GITHUB_ENV" - # TODO: Could be removed once the next step replaces `--commit` with `--install`. + # TODO: Remove once the install step replaces `--commit` with `--install`. - name: Cache Foundry id: cache-foundry uses: actions/cache@v5 @@ -60,6 +60,13 @@ jobs: path: ~/.foundry key: foundry-polkadot-${{ env.CI_FOUNDRY_POLKADOT_COMMIT }} + # TODO: Remove once the install step replaces `--commit` with `--install`. + - name: Install Build Dependencies + if: ${{ steps.cache-foundry.outputs.cache-hit != 'true' }} + run: | + sudo apt-get update + sudo apt-get install -y clang libclang-dev build-essential protobuf-compiler + - name: Install foundryup-polkadot and the Foundry Toolchain if: ${{ steps.cache-foundry.outputs.cache-hit != 'true' }} run: | From 760ec25f4363f3fc77e3d9f14432672fec5d2e8d Mon Sep 17 00:00:00 2001 From: elle-j Date: Wed, 29 Apr 2026 17:18:00 +0200 Subject: [PATCH 08/20] Add wasm32 target for building foundry-polkadot. --- .github/workflows/foundry.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/foundry.yml b/.github/workflows/foundry.yml index 2cf40a3f..2cd5596f 100644 --- a/.github/workflows/foundry.yml +++ b/.github/workflows/foundry.yml @@ -38,6 +38,10 @@ jobs: with: # without this it will override our rust flags rustflags: "" + # TODO: Remove once the foundry install step replaces `--commit` with `--install`. + # Needed for building foundry-polkadot. + target: wasm32-unknown-unknown + components: rust-src - name: Download LLVM uses: ./.github/actions/get-llvm @@ -52,7 +56,7 @@ jobs: make install-bin echo "RESOLC_BIN=$(pwd)/target/release/resolc" >> "$GITHUB_ENV" - # TODO: Remove once the install step replaces `--commit` with `--install`. + # TODO: Remove once the foundry install step replaces `--commit` with `--install`. - name: Cache Foundry id: cache-foundry uses: actions/cache@v5 @@ -60,7 +64,7 @@ jobs: path: ~/.foundry key: foundry-polkadot-${{ env.CI_FOUNDRY_POLKADOT_COMMIT }} - # TODO: Remove once the install step replaces `--commit` with `--install`. + # TODO: Remove once the foundry install step replaces `--commit` with `--install`. - name: Install Build Dependencies if: ${{ steps.cache-foundry.outputs.cache-hit != 'true' }} run: | From ff4199b9ad1be13ef0c3c1284f07b0c9abc00fbf Mon Sep 17 00:00:00 2001 From: elle-j Date: Thu, 30 Apr 2026 10:29:56 +0200 Subject: [PATCH 09/20] Log forge inspect comands. --- .github/workflows/foundry.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/foundry.yml b/.github/workflows/foundry.yml index 2cd5596f..974d31b9 100644 --- a/.github/workflows/foundry.yml +++ b/.github/workflows/foundry.yml @@ -95,11 +95,12 @@ jobs: git clone --depth 1 --branch v1.15.0 \ https://github.com/foundry-rs/forge-std.git "$CI_FOUNDRY_PROJECT_ROOT/lib/forge-std" - - name: Build Project + - name: Compile Project run: forge build --root "$CI_FOUNDRY_PROJECT_ROOT" --use-resolc "$RESOLC_BIN" --optimize -Oz - name: Verify Output run: | + set -x cd "$CI_FOUNDRY_PROJECT_ROOT" forge inspect Counter bytecode | grep -q '^0x50564d' forge inspect Counter deployedBytecode | grep -q '^0x50564d' From db165938f128be57c1ea3c3cf53113f65e88543d Mon Sep 17 00:00:00 2001 From: elle-j Date: Thu, 30 Apr 2026 16:34:58 +0200 Subject: [PATCH 10/20] Replace Counter example project with ERC20. --- .github/workflows/foundry.yml | 28 ++++----- .../foundry/counter/src/Counter.sol | 14 ----- .../foundry/counter/test/Counter.t.sol | 24 -------- .../foundry/{counter => erc20}/foundry.toml | 5 +- .../foundry/erc20/src/MyToken.sol | 17 ++++++ .../foundry/erc20/test/MyToken.t.sol | 61 +++++++++++++++++++ 6 files changed, 96 insertions(+), 53 deletions(-) delete mode 100644 tooling-projects/foundry/counter/src/Counter.sol delete mode 100644 tooling-projects/foundry/counter/test/Counter.t.sol rename tooling-projects/foundry/{counter => erc20}/foundry.toml (73%) create mode 100644 tooling-projects/foundry/erc20/src/MyToken.sol create mode 100644 tooling-projects/foundry/erc20/test/MyToken.t.sol diff --git a/.github/workflows/foundry.yml b/.github/workflows/foundry.yml index 974d31b9..a4fe3edd 100644 --- a/.github/workflows/foundry.yml +++ b/.github/workflows/foundry.yml @@ -19,7 +19,7 @@ env: CARGO_TERM_COLOR: always # Workflow-internal foundry envs are prefixed with `CI_` to not conflict with the # `FOUNDRY_*` namespace, which foundry itself will interpret for its configuration. - CI_FOUNDRY_PROJECT_ROOT: tooling-projects/foundry/counter + CI_FOUNDRY_PROJECT_ROOT: tooling-projects/foundry/erc20 # This is currently the commit that adds support for resolc ">=0.6.0, <2.0.0". # The latest release as of Apr. 28, 2026 supports ">=0.6.0, <0.7.0". # Once a release includes the updated supported versions, this can be changed to a @@ -92,8 +92,8 @@ jobs: - name: Fetch Project Dependencies run: | mkdir -p "$CI_FOUNDRY_PROJECT_ROOT/lib" - git clone --depth 1 --branch v1.15.0 \ - https://github.com/foundry-rs/forge-std.git "$CI_FOUNDRY_PROJECT_ROOT/lib/forge-std" + git clone --depth 1 --branch v1.15.0 https://github.com/foundry-rs/forge-std.git "$CI_FOUNDRY_PROJECT_ROOT/lib/forge-std" + git clone --depth 1 --branch v5.3.0 https://github.com/OpenZeppelin/openzeppelin-contracts.git "$CI_FOUNDRY_PROJECT_ROOT/lib/openzeppelin-contracts" - name: Compile Project run: forge build --root "$CI_FOUNDRY_PROJECT_ROOT" --use-resolc "$RESOLC_BIN" --optimize -Oz @@ -102,17 +102,17 @@ jobs: run: | set -x cd "$CI_FOUNDRY_PROJECT_ROOT" - forge inspect Counter bytecode | grep -q '^0x50564d' - forge inspect Counter deployedBytecode | grep -q '^0x50564d' - forge inspect Counter irOptimized | grep -q . - forge inspect Counter ir | grep -q . - forge inspect Counter assembly | grep -q . - forge inspect Counter abi --json | jq -e 'length > 0' > /dev/null - forge inspect Counter methodIdentifiers --json | jq -e 'length > 0' > /dev/null - forge inspect Counter storageLayout --json | jq -e '.storage | length > 0' > /dev/null - forge inspect Counter metadata --json | jq -e 'length > 0' > /dev/null - forge inspect Counter devdoc --json | jq -e 'length > 0' > /dev/null - forge inspect Counter userdoc --json | jq -e 'length > 0' > /dev/null + forge inspect MyToken bytecode | grep -q '^0x50564d' + forge inspect MyToken deployedBytecode | grep -q '^0x50564d' + forge inspect MyToken irOptimized | grep -q . + forge inspect MyToken ir | grep -q . + forge inspect MyToken assembly | grep -q . + forge inspect MyToken abi --json | jq -e 'length > 0' > /dev/null + forge inspect MyToken methodIdentifiers --json | jq -e 'length > 0' > /dev/null + forge inspect MyToken storageLayout --json | jq -e '.storage | length > 0' > /dev/null + forge inspect MyToken metadata --json | jq -e 'length > 0' > /dev/null + forge inspect MyToken devdoc --json | jq -e 'length > 0' > /dev/null + forge inspect MyToken userdoc --json | jq -e 'length > 0' > /dev/null - name: Test Project run: forge test --root "$CI_FOUNDRY_PROJECT_ROOT" --polkadot=pvm --use-resolc "$RESOLC_BIN" --optimize -Oz -vvvv diff --git a/tooling-projects/foundry/counter/src/Counter.sol b/tooling-projects/foundry/counter/src/Counter.sol deleted file mode 100644 index aded7997..00000000 --- a/tooling-projects/foundry/counter/src/Counter.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.13; - -contract Counter { - uint256 public number; - - function setNumber(uint256 newNumber) public { - number = newNumber; - } - - function increment() public { - number++; - } -} diff --git a/tooling-projects/foundry/counter/test/Counter.t.sol b/tooling-projects/foundry/counter/test/Counter.t.sol deleted file mode 100644 index 48319108..00000000 --- a/tooling-projects/foundry/counter/test/Counter.t.sol +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.13; - -import {Test} from "forge-std/Test.sol"; -import {Counter} from "../src/Counter.sol"; - -contract CounterTest is Test { - Counter public counter; - - function setUp() public { - counter = new Counter(); - counter.setNumber(0); - } - - function test_Increment() public { - counter.increment(); - assertEq(counter.number(), 1); - } - - function testFuzz_SetNumber(uint256 x) public { - counter.setNumber(x); - assertEq(counter.number(), x); - } -} diff --git a/tooling-projects/foundry/counter/foundry.toml b/tooling-projects/foundry/erc20/foundry.toml similarity index 73% rename from tooling-projects/foundry/counter/foundry.toml rename to tooling-projects/foundry/erc20/foundry.toml index 9f907d62..bc428650 100644 --- a/tooling-projects/foundry/counter/foundry.toml +++ b/tooling-projects/foundry/erc20/foundry.toml @@ -3,7 +3,10 @@ src = "src" test = "test" libs = ["lib"] solc = "0.8.34" -remappings = ["forge-std/=lib/forge-std/src/"] +remappings = [ + "forge-std/=lib/forge-std/src/", + "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", +] extra_output = [ "abi", "metadata", diff --git a/tooling-projects/foundry/erc20/src/MyToken.sol b/tooling-projects/foundry/erc20/src/MyToken.sol new file mode 100644 index 00000000..da68dc5c --- /dev/null +++ b/tooling-projects/foundry/erc20/src/MyToken.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.0.0 +pragma solidity ^0.8.22; + +import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; + +contract MyToken is ERC20, Ownable { + constructor(address initialOwner) + ERC20("MyToken", "MTK") + Ownable(initialOwner) + {} + + function mint(address to, uint256 amount) public onlyOwner { + _mint(to, amount); + } +} diff --git a/tooling-projects/foundry/erc20/test/MyToken.t.sol b/tooling-projects/foundry/erc20/test/MyToken.t.sol new file mode 100644 index 00000000..029fce2b --- /dev/null +++ b/tooling-projects/foundry/erc20/test/MyToken.t.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.22; + +import { Test } from "forge-std/Test.sol"; +import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; +import { MyToken } from "../src/MyToken.sol"; + +contract MyTokenTest is Test { + MyToken internal token; + address internal owner = address(this); + address internal alice = address(0xA11CE); + address internal bob = address(0xB0B); + + function setUp() public { + token = new MyToken(owner); + } + + function test_NameAndSymbol() public view { + assertEq(token.name(), "MyToken"); + assertEq(token.symbol(), "MTK"); + } + + function test_Owner() public view { + assertEq(token.owner(), owner); + } + + function test_OwnerCanMint() public { + token.mint(alice, 1000); + assertEq(token.balanceOf(alice), 1000); + } + + function test_NonOwnerCannotMint() public { + vm.prank(alice); + vm.expectRevert( + abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, alice) + ); + token.mint(alice, 1000); + } + + function test_TotalSupplyIncreases() public { + uint256 before = token.totalSupply(); + token.mint(alice, 500); + assertEq(token.totalSupply() - before, 500); + } + + function test_Transfer() public { + token.mint(owner, 1000); + token.transfer(alice, 100); + assertEq(token.balanceOf(alice), 100); + assertEq(token.balanceOf(owner), 900); + } + + function test_TransferFrom() public { + token.mint(owner, 1000); + token.approve(alice, 50); + vm.prank(alice); + token.transferFrom(owner, bob, 50); + assertEq(token.balanceOf(bob), 50); + assertEq(token.allowance(owner, alice), 0); + } +} From cbb566287876c2501cc84cd8e87aa198b8cee79e Mon Sep 17 00:00:00 2001 From: elle-j Date: Thu, 30 Apr 2026 17:08:46 +0200 Subject: [PATCH 11/20] Update cached path and key. --- .github/workflows/foundry.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/foundry.yml b/.github/workflows/foundry.yml index a4fe3edd..dbf5eb6e 100644 --- a/.github/workflows/foundry.yml +++ b/.github/workflows/foundry.yml @@ -61,8 +61,8 @@ jobs: id: cache-foundry uses: actions/cache@v5 with: - path: ~/.foundry - key: foundry-polkadot-${{ env.CI_FOUNDRY_POLKADOT_COMMIT }} + path: ~/.foundry/bin + key: foundry-polkadot-bin-${{ env.CI_FOUNDRY_POLKADOT_COMMIT }} # TODO: Remove once the foundry install step replaces `--commit` with `--install`. - name: Install Build Dependencies From 94c081521c21ac2e47d018a6e9b5161d86a7f573 Mon Sep 17 00:00:00 2001 From: elle-j Date: Fri, 1 May 2026 09:46:45 +0200 Subject: [PATCH 12/20] Replace --root with working-directory. --- .github/workflows/foundry.yml | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/.github/workflows/foundry.yml b/.github/workflows/foundry.yml index dbf5eb6e..af90a8bb 100644 --- a/.github/workflows/foundry.yml +++ b/.github/workflows/foundry.yml @@ -90,18 +90,20 @@ jobs: forge --version - name: Fetch Project Dependencies + working-directory: ${{ env.CI_FOUNDRY_PROJECT_ROOT }} run: | - mkdir -p "$CI_FOUNDRY_PROJECT_ROOT/lib" - git clone --depth 1 --branch v1.15.0 https://github.com/foundry-rs/forge-std.git "$CI_FOUNDRY_PROJECT_ROOT/lib/forge-std" - git clone --depth 1 --branch v5.3.0 https://github.com/OpenZeppelin/openzeppelin-contracts.git "$CI_FOUNDRY_PROJECT_ROOT/lib/openzeppelin-contracts" + mkdir -p lib + git clone --depth 1 --branch v1.15.0 https://github.com/foundry-rs/forge-std.git lib/forge-std + git clone --depth 1 --branch v5.3.0 https://github.com/OpenZeppelin/openzeppelin-contracts.git lib/openzeppelin-contracts - name: Compile Project - run: forge build --root "$CI_FOUNDRY_PROJECT_ROOT" --use-resolc "$RESOLC_BIN" --optimize -Oz + working-directory: ${{ env.CI_FOUNDRY_PROJECT_ROOT }} + run: forge build --use-resolc "$RESOLC_BIN" --optimize -Oz - name: Verify Output + working-directory: ${{ env.CI_FOUNDRY_PROJECT_ROOT }} run: | set -x - cd "$CI_FOUNDRY_PROJECT_ROOT" forge inspect MyToken bytecode | grep -q '^0x50564d' forge inspect MyToken deployedBytecode | grep -q '^0x50564d' forge inspect MyToken irOptimized | grep -q . @@ -115,4 +117,5 @@ jobs: forge inspect MyToken userdoc --json | jq -e 'length > 0' > /dev/null - name: Test Project - run: forge test --root "$CI_FOUNDRY_PROJECT_ROOT" --polkadot=pvm --use-resolc "$RESOLC_BIN" --optimize -Oz -vvvv + working-directory: ${{ env.CI_FOUNDRY_PROJECT_ROOT }} + run: forge test --polkadot=pvm --use-resolc "$RESOLC_BIN" --optimize -Oz -vvvv From 261d6b4e37165585470457eb0914a42a220a4d1d Mon Sep 17 00:00:00 2001 From: elle-j Date: Fri, 1 May 2026 09:50:34 +0200 Subject: [PATCH 13/20] Use return values in transfer test. Warning by forge-lint. --- tooling-projects/foundry/erc20/test/MyToken.t.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tooling-projects/foundry/erc20/test/MyToken.t.sol b/tooling-projects/foundry/erc20/test/MyToken.t.sol index 029fce2b..ed668f60 100644 --- a/tooling-projects/foundry/erc20/test/MyToken.t.sol +++ b/tooling-projects/foundry/erc20/test/MyToken.t.sol @@ -45,7 +45,7 @@ contract MyTokenTest is Test { function test_Transfer() public { token.mint(owner, 1000); - token.transfer(alice, 100); + assertTrue(token.transfer(alice, 100)); assertEq(token.balanceOf(alice), 100); assertEq(token.balanceOf(owner), 900); } @@ -54,7 +54,7 @@ contract MyTokenTest is Test { token.mint(owner, 1000); token.approve(alice, 50); vm.prank(alice); - token.transferFrom(owner, bob, 50); + assertTrue(token.transferFrom(owner, bob, 50)); assertEq(token.balanceOf(bob), 50); assertEq(token.allowance(owner, alice), 0); } From 7524d167765bc48a14386d85fc5a34579f770fed Mon Sep 17 00:00:00 2001 From: elle-j Date: Fri, 1 May 2026 12:04:21 +0200 Subject: [PATCH 14/20] Remove caching of foundry/bin due to forge 'Illegal instruction' on cache hit. --- .github/workflows/foundry.yml | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/.github/workflows/foundry.yml b/.github/workflows/foundry.yml index af90a8bb..29027a14 100644 --- a/.github/workflows/foundry.yml +++ b/.github/workflows/foundry.yml @@ -56,23 +56,16 @@ jobs: make install-bin echo "RESOLC_BIN=$(pwd)/target/release/resolc" >> "$GITHUB_ENV" - # TODO: Remove once the foundry install step replaces `--commit` with `--install`. - - name: Cache Foundry - id: cache-foundry - uses: actions/cache@v5 - with: - path: ~/.foundry/bin - key: foundry-polkadot-bin-${{ env.CI_FOUNDRY_POLKADOT_COMMIT }} - # TODO: Remove once the foundry install step replaces `--commit` with `--install`. - name: Install Build Dependencies - if: ${{ steps.cache-foundry.outputs.cache-hit != 'true' }} run: | sudo apt-get update sudo apt-get install -y clang libclang-dev build-essential protobuf-compiler + # NOTE: ~/.foundry/bin is not cached (which would be very useful when using `--commit`) + # due to forge sometimes crashing with `Illegal instruction` when using the cached + # binaries, seemingly due to the CPU being different when building forge vs running it. - name: Install foundryup-polkadot and the Foundry Toolchain - if: ${{ steps.cache-foundry.outputs.cache-hit != 'true' }} run: | # TODO: Replace `--commit` with `--install` once a release with this commit exists: https://github.com/paritytech/foundry-polkadot/commit/b3173d0584382687cc96b2af072d8cb2addf23d3 From b76187ca43f05b6b04ecfa776a00450b6e833f4a Mon Sep 17 00:00:00 2001 From: elle-j Date: Mon, 4 May 2026 10:39:39 +0200 Subject: [PATCH 15/20] Use solc 0.8.35. --- tooling-projects/foundry/erc20/foundry.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tooling-projects/foundry/erc20/foundry.toml b/tooling-projects/foundry/erc20/foundry.toml index bc428650..59ce13da 100644 --- a/tooling-projects/foundry/erc20/foundry.toml +++ b/tooling-projects/foundry/erc20/foundry.toml @@ -2,7 +2,7 @@ src = "src" test = "test" libs = ["lib"] -solc = "0.8.34" +solc = "0.8.35" remappings = [ "forge-std/=lib/forge-std/src/", "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", From 5e02cb46b0dd1e54caa5981d9851b27188859880 Mon Sep 17 00:00:00 2001 From: elle-j Date: Mon, 4 May 2026 13:17:09 +0200 Subject: [PATCH 16/20] Add explicit --use-resolc as inspect option. --- .github/workflows/foundry.yml | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/.github/workflows/foundry.yml b/.github/workflows/foundry.yml index 29027a14..8ae98232 100644 --- a/.github/workflows/foundry.yml +++ b/.github/workflows/foundry.yml @@ -54,7 +54,7 @@ jobs: - name: Build resolc run: | make install-bin - echo "RESOLC_BIN=$(pwd)/target/release/resolc" >> "$GITHUB_ENV" + echo "RESOLC_PATH=$(pwd)/target/release/resolc" >> $GITHUB_ENV # TODO: Remove once the foundry install step replaces `--commit` with `--install`. - name: Install Build Dependencies @@ -91,24 +91,25 @@ jobs: - name: Compile Project working-directory: ${{ env.CI_FOUNDRY_PROJECT_ROOT }} - run: forge build --use-resolc "$RESOLC_BIN" --optimize -Oz + run: forge build --use-resolc "$RESOLC_PATH" --optimize -Oz - name: Verify Output working-directory: ${{ env.CI_FOUNDRY_PROJECT_ROOT }} run: | + inspect() { forge inspect --use-resolc "$RESOLC_PATH" MyToken "$@"; } set -x - forge inspect MyToken bytecode | grep -q '^0x50564d' - forge inspect MyToken deployedBytecode | grep -q '^0x50564d' - forge inspect MyToken irOptimized | grep -q . - forge inspect MyToken ir | grep -q . - forge inspect MyToken assembly | grep -q . - forge inspect MyToken abi --json | jq -e 'length > 0' > /dev/null - forge inspect MyToken methodIdentifiers --json | jq -e 'length > 0' > /dev/null - forge inspect MyToken storageLayout --json | jq -e '.storage | length > 0' > /dev/null - forge inspect MyToken metadata --json | jq -e 'length > 0' > /dev/null - forge inspect MyToken devdoc --json | jq -e 'length > 0' > /dev/null - forge inspect MyToken userdoc --json | jq -e 'length > 0' > /dev/null + inspect bytecode | grep -q '^0x50564d' + inspect deployedBytecode | grep -q '^0x50564d' + inspect irOptimized | grep -q . + inspect ir | grep -q . + inspect assembly | grep -q . + inspect abi --json | jq -e 'length > 0' > /dev/null + inspect methodIdentifiers --json | jq -e 'length > 0' > /dev/null + inspect storageLayout --json | jq -e '.storage | length > 0' > /dev/null + inspect metadata --json | jq -e 'length > 0' > /dev/null + inspect devdoc --json | jq -e 'length > 0' > /dev/null + inspect userdoc --json | jq -e 'length > 0' > /dev/null - name: Test Project working-directory: ${{ env.CI_FOUNDRY_PROJECT_ROOT }} - run: forge test --polkadot=pvm --use-resolc "$RESOLC_BIN" --optimize -Oz -vvvv + run: forge test --polkadot=pvm --use-resolc "$RESOLC_PATH" --optimize -Oz -vvvv From aaaa01c4386c3cb2f2235d10ca96c3e03492daa7 Mon Sep 17 00:00:00 2001 From: elle-j Date: Tue, 12 May 2026 11:05:07 +0200 Subject: [PATCH 17/20] Reuse the build from differential tests. --- .github/workflows/foundry.yml | 30 ++++++++---------------------- .github/workflows/test.yml | 4 ++++ 2 files changed, 12 insertions(+), 22 deletions(-) diff --git a/.github/workflows/foundry.yml b/.github/workflows/foundry.yml index 8ae98232..b07aa855 100644 --- a/.github/workflows/foundry.yml +++ b/.github/workflows/foundry.yml @@ -1,19 +1,7 @@ name: Foundry Integration on: - push: - branches: ["main"] - paths-ignore: - - "**.md" - pull_request: - branches: ["main"] - types: [opened, synchronize] - paths-ignore: - - "**.md" - -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true + workflow_call: env: CARGO_TERM_COLOR: always @@ -43,18 +31,16 @@ jobs: target: wasm32-unknown-unknown components: rust-src - - name: Download LLVM - uses: ./.github/actions/get-llvm + - name: Download resolc Binary + uses: actions/download-artifact@v4 with: - target: x86_64-unknown-linux-gnu - - - name: Set LLVM Environment Variables - run: echo "LLVM_SYS_221_PREFIX=$(pwd)/llvm-x86_64-unknown-linux-gnu" >> $GITHUB_ENV + name: resolc-x86_64-unknown-linux-musl + path: resolc-bin - - name: Build resolc + - name: Export resolc Path run: | - make install-bin - echo "RESOLC_PATH=$(pwd)/target/release/resolc" >> $GITHUB_ENV + chmod +x resolc-bin/resolc-x86_64-unknown-linux-musl + echo "RESOLC_PATH=$(pwd)/resolc-bin/resolc-x86_64-unknown-linux-musl" >> $GITHUB_ENV # TODO: Remove once the foundry install step replaces `--commit` with `--install`. - name: Install Build Dependencies diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 427600e1..c40148f3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -65,3 +65,7 @@ jobs: # Only run this if `test` successfully completes. needs: test uses: ./.github/workflows/differential-tests.yml + + run-foundry-tests: + needs: run-differential-tests + uses: ./.github/workflows/foundry.yml From 34b7b3b206bb2d91c790c5cf32b2ec6a17ec8625 Mon Sep 17 00:00:00 2001 From: elle-j Date: Tue, 12 May 2026 11:31:45 +0200 Subject: [PATCH 18/20] Move inline script into sh file. --- .github/workflows/foundry.yml | 15 +-------- .../foundry/erc20/verify-compiler-output.sh | 33 +++++++++++++++++++ 2 files changed, 34 insertions(+), 14 deletions(-) create mode 100644 tooling-projects/foundry/erc20/verify-compiler-output.sh diff --git a/.github/workflows/foundry.yml b/.github/workflows/foundry.yml index b07aa855..d8400bc6 100644 --- a/.github/workflows/foundry.yml +++ b/.github/workflows/foundry.yml @@ -81,20 +81,7 @@ jobs: - name: Verify Output working-directory: ${{ env.CI_FOUNDRY_PROJECT_ROOT }} - run: | - inspect() { forge inspect --use-resolc "$RESOLC_PATH" MyToken "$@"; } - set -x - inspect bytecode | grep -q '^0x50564d' - inspect deployedBytecode | grep -q '^0x50564d' - inspect irOptimized | grep -q . - inspect ir | grep -q . - inspect assembly | grep -q . - inspect abi --json | jq -e 'length > 0' > /dev/null - inspect methodIdentifiers --json | jq -e 'length > 0' > /dev/null - inspect storageLayout --json | jq -e '.storage | length > 0' > /dev/null - inspect metadata --json | jq -e 'length > 0' > /dev/null - inspect devdoc --json | jq -e 'length > 0' > /dev/null - inspect userdoc --json | jq -e 'length > 0' > /dev/null + run: bash verify-compiler-output.sh "$RESOLC_PATH" - name: Test Project working-directory: ${{ env.CI_FOUNDRY_PROJECT_ROOT }} diff --git a/tooling-projects/foundry/erc20/verify-compiler-output.sh b/tooling-projects/foundry/erc20/verify-compiler-output.sh new file mode 100644 index 00000000..eab7e8c4 --- /dev/null +++ b/tooling-projects/foundry/erc20/verify-compiler-output.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash + +# Asserts that the compiled project contains the expected compiler output. +# Requires `forge` in PATH. Run from the project's root. +# +# Usage: verify-compiler-output.sh + +set -euxo pipefail + +if [[ $# -ne 1 ]]; then + echo "usage: $(basename "$0") " >&2 + exit 2 +fi + +resolc=$1 + +inspect() { + forge inspect --use-resolc "$resolc" MyToken "$@" +} + +inspect bytecode | grep -q '^0x50564d' +inspect deployedBytecode | grep -q '^0x50564d' +inspect irOptimized | grep -q . +inspect ir | grep -q . +inspect assembly | grep -q . +inspect abi --json | jq -e 'length > 0' > /dev/null +inspect methodIdentifiers --json | jq -e 'length > 0' > /dev/null +inspect storageLayout --json | jq -e '.storage | length > 0' > /dev/null +inspect metadata --json | jq -e 'length > 0' > /dev/null +inspect devdoc --json | jq -e 'length > 0' > /dev/null +inspect userdoc --json | jq -e 'length > 0' > /dev/null + +echo "all checks passed" From 8eec9718f49289f76170a910365f6f34f6491cf4 Mon Sep 17 00:00:00 2001 From: elle-j Date: Tue, 12 May 2026 12:00:23 +0200 Subject: [PATCH 19/20] Add workflow comment. --- .github/workflows/foundry.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/foundry.yml b/.github/workflows/foundry.yml index d8400bc6..042207fa 100644 --- a/.github/workflows/foundry.yml +++ b/.github/workflows/foundry.yml @@ -1,3 +1,6 @@ +# Tests compilation and E2E integration with foundry-polkadot, including basic +# runtime behavior, but not differential runtime correctness. + name: Foundry Integration on: From 86e1b185fe647f75688338dd4e73d9967d5db6fc Mon Sep 17 00:00:00 2001 From: elle-j Date: Tue, 12 May 2026 14:37:49 +0200 Subject: [PATCH 20/20] Fix broken pipe in script. --- .../foundry/erc20/verify-compiler-output.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tooling-projects/foundry/erc20/verify-compiler-output.sh b/tooling-projects/foundry/erc20/verify-compiler-output.sh index eab7e8c4..89530f2b 100644 --- a/tooling-projects/foundry/erc20/verify-compiler-output.sh +++ b/tooling-projects/foundry/erc20/verify-compiler-output.sh @@ -18,11 +18,11 @@ inspect() { forge inspect --use-resolc "$resolc" MyToken "$@" } -inspect bytecode | grep -q '^0x50564d' -inspect deployedBytecode | grep -q '^0x50564d' -inspect irOptimized | grep -q . -inspect ir | grep -q . -inspect assembly | grep -q . +inspect bytecode | grep '^0x50564d' > /dev/null +inspect deployedBytecode | grep '^0x50564d' > /dev/null +inspect irOptimized | grep . > /dev/null +inspect ir | grep . > /dev/null +inspect assembly | grep . > /dev/null inspect abi --json | jq -e 'length > 0' > /dev/null inspect methodIdentifiers --json | jq -e 'length > 0' > /dev/null inspect storageLayout --json | jq -e '.storage | length > 0' > /dev/null