diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 83052d58..d3077665 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -62,8 +62,7 @@ jobs: - name: Check formatting with Black uses: psf/black@stable with: - options: "--check --verbose" - src: "./lib/utils" + options: "--check --verbose scripts lib/utils" codespell: runs-on: ${{ matrix.os }} @@ -107,6 +106,6 @@ jobs: - name: Validate URLs run: | awesome_bot ./*.md src/snekmate/**/*.vy src/snekmate/**/mocks/*.vy src/snekmate/**/interfaces/*.vyi \ - test/**/*.sol test/**/interfaces/*.sol test/**/mocks/*.sol test/**/scripts/*.js lib/utils/*.sol lib/utils/*.py \ + test/**/*.sol test/**/interfaces/*.sol test/**/mocks/*.sol test/**/scripts/*.js lib/utils/*.sol scripts/*.py lib/utils/*.py \ --allow-dupe --allow-redirect --request-delay 0.4 \ --white-list https://www.wagmi.xyz,https://github.com/pcaversaccio/snekmate.git@,https://github.com/pcaversaccio/snekmate/releases/tag/v0.1.1,https://github.com/pcaversaccio/snekmate/blob/v0.1.1,https://github.com/pcaversaccio/snekmate/compare/v0.1.0...v0.1.1,https://hyperelliptic.org diff --git a/.github/workflows/venom-halmos.yml b/.github/workflows/venom-halmos.yml new file mode 100644 index 00000000..0e4e2495 --- /dev/null +++ b/.github/workflows/venom-halmos.yml @@ -0,0 +1,92 @@ +name: ⚗️ Venom-based Halmos symbolic tests + +on: + schedule: + - cron: "30 3 * * *" + workflow_dispatch: + # To be removed before merging. + push: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + halmos: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: + - ubuntu-latest + python_version: + - 3.12 + architecture: + - x64 + halmos: + - "--config test/halmos.toml" + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python_version }} + architecture: ${{ matrix.architecture }} + + - name: Activate `venom` backend + run: python scripts/insert_venom_pragma.py + + - name: Install Vyper + run: pip install vyper + + - name: Show the Vyper version + run: vyper --version + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: nightly + + - name: Install `setuptools` + run: pip install setuptools + + - name: Install Halmos + run: pip install git+https://github.com/a16z/halmos.git@main + + - name: Show the Halmos version + run: halmos --version + + - name: Install Yices 2 SMT solver + run: | + wget -q https://github.com/SRI-CSL/yices2/releases/download/Yices-2.6.4/yices-2.6.4-x86_64-pc-linux-gnu.tar.gz + sudo tar -xzf yices-2.6.4-x86_64-pc-linux-gnu.tar.gz -C /usr/local --strip-components=1 + sudo rm yices-2.6.4-x86_64-pc-linux-gnu.tar.gz + + - name: Show the Foundry Halmos config + run: forge config + env: + FOUNDRY_PROFILE: halmos + + - name: Run Halmos ERC-20 symbolic tests + run: halmos --contract ERC20TestHalmos ${{ matrix.halmos }} + env: + FOUNDRY_PROFILE: halmos + + - name: Run Halmos ERC-721 symbolic tests + run: halmos --contract ERC721TestHalmos ${{ matrix.halmos }} + env: + FOUNDRY_PROFILE: halmos + + - name: Run Halmos ERC-1155 symbolic tests + run: halmos --contract ERC1155TestHalmos ${{ matrix.halmos }} + env: + FOUNDRY_PROFILE: halmos + + - name: Run Halmos math symbolic tests + run: halmos --contract MathTestHalmos ${{ matrix.halmos }} + env: + FOUNDRY_PROFILE: halmos diff --git a/.github/workflows/venom-test-contracts.yml b/.github/workflows/venom-test-contracts.yml new file mode 100644 index 00000000..543dacfd --- /dev/null +++ b/.github/workflows/venom-test-contracts.yml @@ -0,0 +1,132 @@ +name: 🧪 Venom-based smart contract tests + +on: [push, pull_request, workflow_dispatch] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + tests: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: + - ubuntu-latest + python_version: + - 3.12 + architecture: + - x64 + node_version: + - 20 + echidna: + - "--config test/echidna.yaml" + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python_version }} + architecture: ${{ matrix.architecture }} + + - name: Activate `venom` backend + run: python scripts/insert_venom_pragma.py + + - name: Setup Ape + uses: ApeWorX/github-action@v3 + with: + python-version: ${{ matrix.python_version }} + + - name: Check Ape compilation + run: ape compile + + - name: Remove Ape Vyper and install latest Vyper + run: pip install --force-reinstall vyper + + - name: Show the Vyper version + run: vyper --version + + - name: Install pnpm + uses: pnpm/action-setup@v3 + with: + version: latest + run_install: false + + - name: Get pnpm cache directory path + id: pnpm-cache-dir-path + run: echo "dir=$(pnpm store path --silent)" >> $GITHUB_OUTPUT + + - name: Restore pnpm cache + uses: actions/cache@v4 + id: pnpm-cache + with: + path: ${{ steps.pnpm-cache-dir-path.outputs.dir }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: ${{ runner.os }}-pnpm-store- + + - name: Use Node.js ${{ matrix.node_version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node_version }} + + - name: Install pnpm project with a clean slate + run: pnpm install --prefer-offline --frozen-lockfile + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: nightly + + - name: Show the Foundry CI config + run: forge config + env: + FOUNDRY_PROFILE: ci + + - name: Foundry tests + run: forge test + env: + FOUNDRY_PROFILE: ci + + - name: Show the Foundry default config + run: forge config + env: + FOUNDRY_PROFILE: default + + - name: Run snapshot + run: NO_COLOR=1 forge snapshot >> $GITHUB_STEP_SUMMARY + env: + FOUNDRY_PROFILE: default + + - name: Install Homebrew + uses: Homebrew/actions/setup-homebrew@master + + - name: Install Echidna + run: brew install echidna + + - name: Show the Echidna version + run: echidna --version + + - name: Show the Foundry Echidna config + run: forge config + env: + FOUNDRY_PROFILE: echidna + + - name: Compile the Echidna test contracts + run: forge build --build-info + env: + FOUNDRY_PROFILE: echidna + + - name: Run Echidna ERC-20 property tests + run: echidna test/tokens/echidna/ERC20Properties.sol --contract CryticERC20ExternalHarness ${{ matrix.echidna }} + env: + FOUNDRY_PROFILE: echidna + + - name: Run Echidna ERC-721 property tests + run: echidna test/tokens/echidna/ERC721Properties.sol --contract CryticERC721ExternalHarness ${{ matrix.echidna }} + env: + FOUNDRY_PROFILE: echidna diff --git a/scripts/insert_venom_pragma.py b/scripts/insert_venom_pragma.py new file mode 100644 index 00000000..4f700bba --- /dev/null +++ b/scripts/insert_venom_pragma.py @@ -0,0 +1,29 @@ +import os + + +def add_venom_pragma(filepath): + with open(filepath, "r") as file: + lines = file.readlines() + + # Insert `pragma experimental-codegen` in the second line to activate the `venom` backend. + if len(lines) >= 2: + lines.insert(1, "# pragma experimental-codegen\n") + else: + lines.append("# pragma experimental-codegen\n") + + # Write the modified lines back to the file. + with open(filepath, "w") as file: + file.writelines(lines) + + +def process_directory(directory): + for root, _, files in os.walk(directory): + for file in files: + if file.endswith(".vy") or file.endswith(".vyi"): + filepath = os.path.join(root, file) + add_venom_pragma(filepath) + + +if __name__ == "__main__": + src_directory = "src/snekmate" + process_directory(src_directory)