diff --git a/.cargo/config.toml b/.cargo/config.toml index 59534b2352ac..e7f653d39dcc 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,13 +1,15 @@ [target.x86_64-pc-windows-msvc] rustflags = [ - # Increases the stack size to 10MB, which is - # in line with Linux (whereas default for Windows is 1MB) - "-C", "link-arg=/STACK:10000000" + # Increases the stack size to 10MB, which is + # in line with Linux (whereas default for Windows is 1MB) + "-C", + "link-arg=/STACK:10000000", ] [target.i686-pc-windows-msvc] rustflags = [ - # Increases the stack size to 10MB, which is - # in line with Linux (whereas default for Windows is 1MB) - "-C", "link-arg=/STACK:10000000" + # Increases the stack size to 10MB, which is + # in line with Linux (whereas default for Windows is 1MB) + "-C", + "link-arg=/STACK:10000000", ] diff --git a/.github/ISSUE_TEMPLATE/BUG-FORM.yml b/.github/ISSUE_TEMPLATE/BUG-FORM.yml index 551e2b83b00a..d96745ed8586 100644 --- a/.github/ISSUE_TEMPLATE/BUG-FORM.yml +++ b/.github/ISSUE_TEMPLATE/BUG-FORM.yml @@ -2,54 +2,52 @@ name: Bug report description: File a bug report labels: ["T-bug"] body: - - type: markdown - attributes: - value: | - Please ensure that the bug has not already been filed in the issue tracker. + - type: markdown + attributes: + value: | + Please ensure that the bug has not already been filed in the issue tracker. - Thanks for taking the time to report this bug! - - type: dropdown - attributes: - label: Component - description: What component is the bug in? - multiple: true - options: - - Forge - - Cast - - Anvil - - Foundryup - - Other (please describe) - validations: - required: true - - type: checkboxes - attributes: - label: Have you ensured that all of these are up to date? - options: - - label: Foundry - - label: Foundryup - validations: - required: true - - type: input - attributes: - label: What version of Foundry are you on? - placeholder: "Run forge --version and paste the output here" - - type: input - attributes: - label: What command(s) is the bug in? - description: Leave empty if not relevant - placeholder: "For example: forge test" - - type: dropdown - attributes: - label: Operating System - description: What operating system are you on? - options: - - Windows - - macOS (Intel) - - macOS (Apple Silicon) - - Linux - - type: textarea - attributes: - label: Describe the bug - description: Please include relevant Solidity snippets as well if relevant. - validations: - required: true + Thanks for taking the time to report this bug! + - type: dropdown + attributes: + label: Component + description: What component is the bug in? + multiple: true + options: + - Forge + - Cast + - Anvil + - Foundryup + - Other (please describe) + validations: + required: true + - type: checkboxes + attributes: + label: Have you ensured that all of these are up to date? + options: + - label: Foundry + - label: Foundryup + - type: input + attributes: + label: What version of Foundry are you on? + placeholder: "Run forge --version and paste the output here" + - type: input + attributes: + label: What command(s) is the bug in? + description: Leave empty if not relevant + placeholder: "For example: forge test" + - type: dropdown + attributes: + label: Operating System + description: What operating system are you on? + options: + - Windows + - macOS (Intel) + - macOS (Apple Silicon) + - Linux + - type: textarea + attributes: + label: Describe the bug + description: Please include relevant Solidity snippets as well if relevant. + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/FEATURE-FORM.yml b/.github/ISSUE_TEMPLATE/FEATURE-FORM.yml index 26ac1eb27dd0..40102b65eb80 100644 --- a/.github/ISSUE_TEMPLATE/FEATURE-FORM.yml +++ b/.github/ISSUE_TEMPLATE/FEATURE-FORM.yml @@ -2,32 +2,32 @@ name: Feature request description: Suggest a feature labels: ["T-feature"] body: - - type: markdown - attributes: - value: | - Please ensure that the feature has not already been requested in the issue tracker. + - type: markdown + attributes: + value: | + Please ensure that the feature has not already been requested in the issue tracker. - Thanks for helping us improve Foundry! - - type: dropdown - attributes: - label: Component - description: What component is the feature for? - multiple: true - options: - - Forge - - Cast - - Anvil - - Foundryup - - Other (please describe) - validations: - required: true - - type: textarea - attributes: - label: Describe the feature you would like - description: Please also describe what the feature is aiming to solve, if relevant. - validations: - required: true - - type: textarea - attributes: - label: Additional context - description: Add any other context to the feature (like screenshots, resources) + Thanks for helping us improve Foundry! + - type: dropdown + attributes: + label: Component + description: What component is the feature for? + multiple: true + options: + - Forge + - Cast + - Anvil + - Foundryup + - Other (please describe) + validations: + required: true + - type: textarea + attributes: + label: Describe the feature you would like + description: Please also describe what the feature is aiming to solve, if relevant. + validations: + required: true + - type: textarea + attributes: + label: Additional context + description: Add any other context to the feature (like screenshots, resources) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 4241e8f2a134..201877db6bc5 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,5 @@ blank_issues_enabled: true contact_links: - - name: Support - url: https://t.me/foundry_support - about: This issue tracker is only for bugs and feature requests. Support is available on Telegram! + - name: Support + url: https://t.me/foundry_support + about: This issue tracker is only for bugs and feature requests. Support is available on Telegram! diff --git a/.github/changelog.json b/.github/changelog.json index 10788b102f48..4fe255e699ee 100644 --- a/.github/changelog.json +++ b/.github/changelog.json @@ -1,15 +1,16 @@ { - "categories": [{ - "title": "## Features", - "labels": ["T-feature"] - }, { - "title": "## Fixes", - "labels": ["T-bug", "T-fix"] - }], - "ignore_labels": [ - "L-ignore" - ], - "template": "${{CHANGELOG}}\n## Other\n\n${{UNCATEGORIZED}}", - "pr_template": "- ${{TITLE}} (#${{NUMBER}})", - "empty_template": "- No changes" + "categories": [ + { + "title": "## Features", + "labels": ["T-feature"] + }, + { + "title": "## Fixes", + "labels": ["T-bug", "T-fix"] + } + ], + "ignore_labels": ["L-ignore"], + "template": "${{CHANGELOG}}\n## Other\n\n${{UNCATEGORIZED}}", + "pr_template": "- ${{TITLE}} (#${{NUMBER}})", + "empty_template": "- No changes" } diff --git a/.github/scripts/create-tag.js b/.github/scripts/create-tag.js index 457a4df3fb4f..042f9950f617 100644 --- a/.github/scripts/create-tag.js +++ b/.github/scripts/create-tag.js @@ -1,14 +1,14 @@ -module.exports = async ({github, context}, tagName) => { - try { - await github.rest.git.createRef({ - owner: context.repo.owner, - repo: context.repo.repo, - ref: `refs/tags/${tagName}`, - sha: context.sha, - force: true - }) - } catch (err) { - console.error(`Failed to create tag: ${tagName}`) - console.error(err) - } -} +module.exports = async ({ github, context }, tagName) => { + try { + await github.rest.git.createRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: `refs/tags/${tagName}`, + sha: context.sha, + force: true, + }); + } catch (err) { + console.error(`Failed to create tag: ${tagName}`); + console.error(err); + } +}; diff --git a/.github/scripts/move-tag.js b/.github/scripts/move-tag.js index 907993615821..d1fe815be57c 100644 --- a/.github/scripts/move-tag.js +++ b/.github/scripts/move-tag.js @@ -1,15 +1,15 @@ -module.exports = async ({github, context}, tagName) => { - try { - await github.rest.git.updateRef({ - owner: context.repo.owner, - repo: context.repo.repo, - ref: `tags/${tagName}`, - sha: context.sha, - force: true - }) - } catch (err) { - console.error(`Failed to move nightly tag.`) - console.error(`This should only happen the first time.`) - console.error(err) - } -} +module.exports = async ({ github, context }, tagName) => { + try { + await github.rest.git.updateRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: `tags/${tagName}`, + sha: context.sha, + force: true, + }); + } catch (err) { + console.error(`Failed to move nightly tag.`); + console.error(`This should only happen the first time.`); + console.error(err); + } +}; diff --git a/.github/scripts/prune-prereleases.js b/.github/scripts/prune-prereleases.js index c18560ccbb8a..ff0df46af53f 100644 --- a/.github/scripts/prune-prereleases.js +++ b/.github/scripts/prune-prereleases.js @@ -1,33 +1,33 @@ -module.exports = async ({github, context}) => { - console.log('Pruning old prereleases') +module.exports = async ({ github, context }) => { + console.log("Pruning old prereleases"); - const { data: releases } = await github.rest.repos.listReleases({ - owner: context.repo.owner, - repo: context.repo.repo - }) + const { data: releases } = await github.rest.repos.listReleases({ + owner: context.repo.owner, + repo: context.repo.repo, + }); - // Only consider releases tagged `nightly-${SHA}` for deletion - let nightlies = releases.filter( - (release) => release.tag_name.includes('nightly') && release.tag_name !== 'nightly' - ) + // Only consider releases tagged `nightly-${SHA}` for deletion + let nightlies = releases.filter( + release => release.tag_name.includes("nightly") && release.tag_name !== "nightly" + ); - // Keep newest 3 nightlies - nightlies = nightlies.slice(3) + // Keep newest 3 nightlies + nightlies = nightlies.slice(3); - for (const nightly of nightlies) { - console.log(`Deleting nightly: ${nightly.tag_name}`) - await github.rest.repos.deleteRelease({ - owner: context.repo.owner, - repo: context.repo.repo, - release_id: nightly.id - }) - console.log(`Deleting nightly tag: ${nightly.tag_name}`) - await github.rest.git.deleteRef({ - owner: context.repo.owner, - repo: context.repo.repo, - ref: `tags/${nightly.tag_name}` - }) - } + for (const nightly of nightlies) { + console.log(`Deleting nightly: ${nightly.tag_name}`); + await github.rest.repos.deleteRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + release_id: nightly.id, + }); + console.log(`Deleting nightly tag: ${nightly.tag_name}`); + await github.rest.git.deleteRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: `tags/${nightly.tag_name}`, + }); + } - console.log('Done.') -} + console.log("Done."); +}; diff --git a/.github/workflows/cross-platform.yml b/.github/workflows/cross-platform.yml index d25978025c2e..b96d8c19dff7 100644 --- a/.github/workflows/cross-platform.yml +++ b/.github/workflows/cross-platform.yml @@ -1,196 +1,196 @@ on: - workflow_dispatch: - workflow_call: + workflow_dispatch: + workflow_call: name: cross-platform env: - CARGO_TERM_COLOR: always + CARGO_TERM_COLOR: always jobs: - build-tests: - name: building ${{ matrix.job.target }} (${{ matrix.job.os }}) / ${{ matrix.archive.name }} - runs-on: ${{ matrix.job.os }} - timeout-minutes: 60 - strategy: - fail-fast: false - matrix: - archive: - - name: unit-tests - file: nextest-unit.tar.zst - flags: --workspace --all-features --lib --bins - - name: integration-tests - file: nextest-integration.tar.zst - flags: --workspace - job: - # The OS is used for the runner - # The target is used by Cargo - - os: ubuntu-latest - target: x86_64-unknown-linux-gnu - - os: ubuntu-latest - target: aarch64-unknown-linux-gnu - - os: macos-latest - target: x86_64-apple-darwin - - os: macos-latest - target: aarch64-apple-darwin - - os: windows-latest - target: x86_64-pc-windows-msvc - - steps: - - name: Checkout sources - uses: actions/checkout@v2 - - - name: Install Rust toolchain - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - target: ${{ matrix.job.target }} - override: true - profile: minimal - - - uses: Swatinem/rust-cache@v1 - with: - cache-on-failure: true - - name: Install nextest - uses: taiki-e/install-action@nextest - - # Required for forge commands that use git - - name: Setup git - run: | - git config --global user.name "GitHub Actions Bot" - git config --global user.email "<>" - - - name: Apple M1 setup - if: ${{ matrix.job.target == 'aarch64-apple-darwin' }} - run: | - echo "SDKROOT=$(xcrun -sdk macosx --show-sdk-path)" >> $GITHUB_ENV - echo "MACOSX_DEPLOYMENT_TARGET=$(xcrun -sdk macosx --show-sdk-platform-version)" >> $GITHUB_ENV - - - name: Linux ARM setup - if: ${{ matrix.job.target == 'aarch64-unknown-linux-gnu' }} - run: | - sudo apt-get update -y - sudo apt-get install -y gcc-aarch64-linux-gnu - echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV - - # For some reason the FFI cheatcode uses WSL bash instead of Git bash, so we need to install a WSL distribution - - name: Windows setup - if: ${{ matrix.job.target == 'x86_64-pc-windows-msvc' }} - run: | - wsl --install --distribution Ubuntu - shell: pwsh - - - name: Build archive (unit tests) - run: cargo nextest archive --locked ${{ matrix.job.flags }} --archive-file ${{ matrix.job.target }}-${{ matrix.archive.file }} - - name: Upload archive - uses: actions/upload-artifact@v3 - with: - name: ${{ matrix.job.target }}-${{ matrix.archive.name }} - path: ${{ matrix.job.target }}-${{ matrix.archive.file }} - - unit: - name: unit tests ${{ matrix.job.target }} (${{ matrix.job.os }}) / ${{ matrix.archive.name }} / ${{ matrix.nextest.name }} - runs-on: ${{ matrix.job.os }} - needs: build-tests - timeout-minutes: 60 - strategy: - fail-fast: false - matrix: - archive: - - name: unit-tests - file: nextest-unit.tar.zst - job: - # The OS is used for the runner - # The target is used by Cargo - - os: ubuntu-latest - target: x86_64-unknown-linux-gnu - - os: ubuntu-latest - target: aarch64-unknown-linux-gnu - - os: macos-latest - target: x86_64-apple-darwin - - os: macos-latest - target: aarch64-apple-darwin - - os: windows-latest - target: x86_64-pc-windows-msvc - nextest: - - name: non-forking - filter: '!test(~fork) & !test(~live) & !test(~forge_std) & !test(~deploy_and_simulate)' - env: - ETH_RPC_URL: https://eth-mainnet.alchemyapi.io/v2/C3JEvfW6VgtqZQa-Qp1E-2srEiIc02sD - steps: - - name: Checkout sources - uses: actions/checkout@v2 - - name: Install nextest - uses: taiki-e/install-action@nextest - - name: Download archives - uses: actions/download-artifact@v3 - with: - name: ${{ matrix.job.target }}-${{ matrix.archive.name }} - - name: Setup git config - run: | - git config --global user.name "GitHub Actions Bot" - git config --global user.email "<>" - - - name: cargo nextest - run: ~/.cargo/bin/cargo-nextest nextest run --retries 3 --archive-file ${{ matrix.job.target }}-${{ matrix.archive.file }} -E '${{ matrix.nextest.filter }}' - - integration: - name: integration tests ${{ matrix.job.target }} (${{ matrix.job.os }}) / ${{ matrix.archive.name }} / ${{ matrix.nextest.name }} - runs-on: ${{ matrix.job.os }} - timeout-minutes: 60 - needs: build-tests - strategy: - fail-fast: false - matrix: - archive: - - name: integration-tests - file: nextest-integration.tar.zst - job: - # The OS is used for the runner - # The target is used by Cargo - - os: ubuntu-latest - target: x86_64-unknown-linux-gnu - - os: ubuntu-latest - target: aarch64-unknown-linux-gnu - - os: macos-latest - target: x86_64-apple-darwin - - os: macos-latest - target: aarch64-apple-darwin - - os: windows-latest - target: x86_64-pc-windows-msvc - nextest: - - name: non-forking - # skip fork,verify,forge-std and script tests that use heavy simulation - filter: '!test(~fork) & !test(~live) & !test(~forge_std) & !test(~deploy_and_simulate)' - # the aarch64-apple-darwin runner is particularly slow with script related tests - macos-aarch-filter: '!test(~fork) & !test(~live) & !test(~forge_std) & !test(~deploy_)' - env: - ETH_RPC_URL: https://eth-mainnet.alchemyapi.io/v2/C3JEvfW6VgtqZQa-Qp1E-2srEiIc02sD - steps: - - name: Checkout sources - uses: actions/checkout@v2 - - name: Install nextest - uses: taiki-e/install-action@nextest - - name: Download archives - uses: actions/download-artifact@v3 - with: - name: ${{ matrix.job.target }}-${{ matrix.archive.name }} - - - name: Forge RPC cache - uses: actions/cache@v3 - if: matrix.nextest.name != 'non-forking' - with: - path: "$HOME/.foundry/cache" - key: rpc-cache-${{ hashFiles('cli/tests/rpc-cache-keyfile') }} - - name: Setup git config - run: | - git config --global user.name "GitHub Actions Bot" - git config --global user.email "<>" - - - name: cargo nextest - if: ${{ matrix.job.target == 'aarch64-apple-darwin' }} - run: ~/.cargo/bin/cargo-nextest nextest run --retries 3 --archive-file ${{ matrix.job.target }}-${{ matrix.archive.file }} -E '${{ matrix.nextest. macos-aarch-filter }}' - - - name: cargo nextest - if: ${{ matrix.job.target != 'aarch64-apple-darwin' }} - run: ~/.cargo/bin/cargo-nextest nextest run --retries 3 --archive-file ${{ matrix.job.target }}-${{ matrix.archive.file }} -E '${{ matrix.nextest.filter }}' \ No newline at end of file + build-tests: + name: building ${{ matrix.job.target }} (${{ matrix.job.os }}) / ${{ matrix.archive.name }} + runs-on: ${{ matrix.job.os }} + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + archive: + - name: unit-tests + file: nextest-unit.tar.zst + flags: --workspace --all-features --lib --bins + - name: integration-tests + file: nextest-integration.tar.zst + flags: --workspace + job: + # The OS is used for the runner + # The target is used by Cargo + - os: ubuntu-latest + target: x86_64-unknown-linux-gnu + - os: ubuntu-latest + target: aarch64-unknown-linux-gnu + - os: macos-latest + target: x86_64-apple-darwin + - os: macos-latest + target: aarch64-apple-darwin + - os: windows-latest + target: x86_64-pc-windows-msvc + + steps: + - name: Checkout sources + uses: actions/checkout@v2 + + - name: Install Rust toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + target: ${{ matrix.job.target }} + override: true + profile: minimal + + - uses: Swatinem/rust-cache@v1 + with: + cache-on-failure: true + - name: Install nextest + uses: taiki-e/install-action@nextest + + # Required for forge commands that use git + - name: Setup git + run: | + git config --global user.name "GitHub Actions Bot" + git config --global user.email "<>" + + - name: Apple M1 setup + if: ${{ matrix.job.target == 'aarch64-apple-darwin' }} + run: | + echo "SDKROOT=$(xcrun -sdk macosx --show-sdk-path)" >> $GITHUB_ENV + echo "MACOSX_DEPLOYMENT_TARGET=$(xcrun -sdk macosx --show-sdk-platform-version)" >> $GITHUB_ENV + + - name: Linux ARM setup + if: ${{ matrix.job.target == 'aarch64-unknown-linux-gnu' }} + run: | + sudo apt-get update -y + sudo apt-get install -y gcc-aarch64-linux-gnu + echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV + + # For some reason the FFI cheatcode uses WSL bash instead of Git bash, so we need to install a WSL distribution + - name: Windows setup + if: ${{ matrix.job.target == 'x86_64-pc-windows-msvc' }} + run: | + wsl --install --distribution Ubuntu + shell: pwsh + + - name: Build archive (unit tests) + run: cargo nextest archive --locked ${{ matrix.job.flags }} --archive-file ${{ matrix.job.target }}-${{ matrix.archive.file }} + - name: Upload archive + uses: actions/upload-artifact@v3 + with: + name: ${{ matrix.job.target }}-${{ matrix.archive.name }} + path: ${{ matrix.job.target }}-${{ matrix.archive.file }} + + unit: + name: unit tests ${{ matrix.job.target }} (${{ matrix.job.os }}) / ${{ matrix.archive.name }} / ${{ matrix.nextest.name }} + runs-on: ${{ matrix.job.os }} + needs: build-tests + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + archive: + - name: unit-tests + file: nextest-unit.tar.zst + job: + # The OS is used for the runner + # The target is used by Cargo + - os: ubuntu-latest + target: x86_64-unknown-linux-gnu + - os: ubuntu-latest + target: aarch64-unknown-linux-gnu + - os: macos-latest + target: x86_64-apple-darwin + - os: macos-latest + target: aarch64-apple-darwin + - os: windows-latest + target: x86_64-pc-windows-msvc + nextest: + - name: non-forking + filter: "!test(~fork) & !test(~live) & !test(~forge_std) & !test(~deploy_and_simulate)" + env: + ETH_RPC_URL: https://eth-mainnet.alchemyapi.io/v2/C3JEvfW6VgtqZQa-Qp1E-2srEiIc02sD + steps: + - name: Checkout sources + uses: actions/checkout@v2 + - name: Install nextest + uses: taiki-e/install-action@nextest + - name: Download archives + uses: actions/download-artifact@v3 + with: + name: ${{ matrix.job.target }}-${{ matrix.archive.name }} + - name: Setup git config + run: | + git config --global user.name "GitHub Actions Bot" + git config --global user.email "<>" + + - name: cargo nextest + run: ~/.cargo/bin/cargo-nextest nextest run --retries 3 --archive-file ${{ matrix.job.target }}-${{ matrix.archive.file }} -E '${{ matrix.nextest.filter }}' + + integration: + name: integration tests ${{ matrix.job.target }} (${{ matrix.job.os }}) / ${{ matrix.archive.name }} / ${{ matrix.nextest.name }} + runs-on: ${{ matrix.job.os }} + timeout-minutes: 60 + needs: build-tests + strategy: + fail-fast: false + matrix: + archive: + - name: integration-tests + file: nextest-integration.tar.zst + job: + # The OS is used for the runner + # The target is used by Cargo + - os: ubuntu-latest + target: x86_64-unknown-linux-gnu + - os: ubuntu-latest + target: aarch64-unknown-linux-gnu + - os: macos-latest + target: x86_64-apple-darwin + - os: macos-latest + target: aarch64-apple-darwin + - os: windows-latest + target: x86_64-pc-windows-msvc + nextest: + - name: non-forking + # skip fork,verify,forge-std and script tests that use heavy simulation + filter: "!test(~fork) & !test(~live) & !test(~forge_std) & !test(~deploy_and_simulate)" + # the aarch64-apple-darwin runner is particularly slow with script related tests + macos-aarch-filter: "!test(~fork) & !test(~live) & !test(~forge_std) & !test(~deploy_)" + env: + ETH_RPC_URL: https://eth-mainnet.alchemyapi.io/v2/C3JEvfW6VgtqZQa-Qp1E-2srEiIc02sD + steps: + - name: Checkout sources + uses: actions/checkout@v2 + - name: Install nextest + uses: taiki-e/install-action@nextest + - name: Download archives + uses: actions/download-artifact@v3 + with: + name: ${{ matrix.job.target }}-${{ matrix.archive.name }} + + - name: Forge RPC cache + uses: actions/cache@v3 + if: matrix.nextest.name != 'non-forking' + with: + path: "$HOME/.foundry/cache" + key: rpc-cache-${{ hashFiles('cli/tests/rpc-cache-keyfile') }} + - name: Setup git config + run: | + git config --global user.name "GitHub Actions Bot" + git config --global user.email "<>" + + - name: cargo nextest + if: ${{ matrix.job.target == 'aarch64-apple-darwin' }} + run: ~/.cargo/bin/cargo-nextest nextest run --retries 3 --archive-file ${{ matrix.job.target }}-${{ matrix.archive.file }} -E '${{ matrix.nextest. macos-aarch-filter }}' + + - name: cargo nextest + if: ${{ matrix.job.target != 'aarch64-apple-darwin' }} + run: ~/.cargo/bin/cargo-nextest nextest run --retries 3 --archive-file ${{ matrix.job.target }}-${{ matrix.archive.file }} -E '${{ matrix.nextest.filter }}' diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index ba0b8f792943..6f78efbed6f7 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -1,93 +1,92 @@ name: Build and Publish Docker -on: - # Trigger without any parameters a proactive rebuild - workflow_dispatch: {} - workflow_call: +on: + # Trigger without any parameters a proactive rebuild + workflow_dispatch: {} + workflow_call: env: - REGISTRY: ghcr.io - # Will resolve to foundry-rs/foundry - IMAGE_NAME: ${{ github.repository }} + REGISTRY: ghcr.io + # Will resolve to foundry-rs/foundry + IMAGE_NAME: ${{ github.repository }} jobs: - container: + container: + runs-on: ubuntu-latest + # https://docs.github.com/en/actions/reference/authentication-in-a-workflow + permissions: + id-token: write + packages: write + contents: read + timeout-minutes: 60 - runs-on: ubuntu-latest - # https://docs.github.com/en/actions/reference/authentication-in-a-workflow - permissions: - id-token: write - packages: write - contents: read - timeout-minutes: 60 + steps: + - name: Checkout repository + id: checkout + uses: actions/checkout@v3 - steps: - - name: Checkout repository - id: checkout - uses: actions/checkout@v3 + - name: Install Docker BuildX + uses: docker/setup-buildx-action@v2 + id: buildx + with: + install: true - - name: Install Docker BuildX - uses: docker/setup-buildx-action@v2 - id: buildx - with: - install: true + # Login against a Docker registry except on PR + # https://github.com/docker/login-action + - name: Log into registry ${{ env.REGISTRY }} + # Ensure this doesn't trigger on PR's + if: github.event_name != 'pull_request' + uses: docker/login-action@v2 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} - # Login against a Docker registry except on PR - # https://github.com/docker/login-action - - name: Log into registry ${{ env.REGISTRY }} - # Ensure this doesn't trigger on PR's - if: github.event_name != 'pull_request' - uses: docker/login-action@v2 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} + # Extract metadata (tags, labels) for Docker + # https://github.com/docker/metadata-action + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@v4 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - # Extract metadata (tags, labels) for Docker - # https://github.com/docker/metadata-action - - name: Extract Docker metadata - id: meta - uses: docker/metadata-action@v4 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + # Creates an additional 'latest' or 'nightly' tag + # If the job is triggered via cron schedule, tag nightly and nightly-{SHA} + # If the job is triggered via workflow dispatch and on a master branch, tag branch and latest + # Otherwise, just tag as the branch name + - name: Finalize Docker Metadata + id: docker_tagging + run: | + if [[ "${{ github.event_name }}" == 'schedule' ]]; then + echo "cron trigger, assigning nightly tag" + echo "::set-output name=docker_tags::${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:nightly,${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:nightly-${GITHUB_SHA}" + elif [[ "${GITHUB_REF##*/}" == "main" ]] || [[ ${GITHUB_REF##*/} == "master" ]]; then + echo "manual trigger from master/main branch, assigning latest tag" + echo "::set-output name=docker_tags::${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${GITHUB_REF##*/},${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest" + else + echo "Neither scheduled nor manual release from main branch. Just tagging as branch name" + echo "::set-output name=docker_tags::${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${GITHUB_REF##*/}" + fi - # Creates an additional 'latest' or 'nightly' tag - # If the job is triggered via cron schedule, tag nightly and nightly-{SHA} - # If the job is triggered via workflow dispatch and on a master branch, tag branch and latest - # Otherwise, just tag as the branch name - - name: Finalize Docker Metadata - id: docker_tagging - run: | - if [[ "${{ github.event_name }}" == 'schedule' ]]; then - echo "cron trigger, assigning nightly tag" - echo "::set-output name=docker_tags::${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:nightly,${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:nightly-${GITHUB_SHA}" - elif [[ "${GITHUB_REF##*/}" == "main" ]] || [[ ${GITHUB_REF##*/} == "master" ]]; then - echo "manual trigger from master/main branch, assigning latest tag" - echo "::set-output name=docker_tags::${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${GITHUB_REF##*/},${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest" - else - echo "Neither scheduled nor manual release from main branch. Just tagging as branch name" - echo "::set-output name=docker_tags::${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${GITHUB_REF##*/}" - fi + # Log docker metadata to explicitly know what is being pushed + - name: Inspect Docker Metadata + run: | + echo "TAGS -> ${{ steps.docker_tagging.outputs.docker_tags }}" + echo "LABELS -> ${{ steps.meta.outputs.labels }}" - # Log docker metadata to explicitly know what is being pushed - - name: Inspect Docker Metadata - run: | - echo "TAGS -> ${{ steps.docker_tagging.outputs.docker_tags }}" - echo "LABELS -> ${{ steps.meta.outputs.labels }}" - - # Build and push Docker image - # https://github.com/docker/build-push-action - # https://github.com/docker/build-push-action/blob/master/docs/advanced/cache.md - - name: Build and push Docker image - uses: docker/build-push-action@v3 - with: - context: . - push: true - tags: ${{ steps.docker_tagging.outputs.docker_tags }} - labels: ${{ steps.meta.outputs.labels }} - cache-from: type=gha - cache-to: type=gha,mode=max - build-args: | - BUILDTIME=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }} - VERSION=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.version'] }} - REVISION=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.revision'] }} + # Build and push Docker image + # https://github.com/docker/build-push-action + # https://github.com/docker/build-push-action/blob/master/docs/advanced/cache.md + - name: Build and push Docker image + uses: docker/build-push-action@v3 + with: + context: . + push: true + tags: ${{ steps.docker_tagging.outputs.docker_tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + build-args: | + BUILDTIME=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }} + VERSION=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.version'] }} + REVISION=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.revision'] }} diff --git a/.github/workflows/live-test.yml b/.github/workflows/live-test.yml index 0de0b8cebd7e..6dbd397e1972 100644 --- a/.github/workflows/live-test.yml +++ b/.github/workflows/live-test.yml @@ -1,33 +1,33 @@ on: - push: - branches: - - master + push: + branches: + - master name: live-test env: - CARGO_TERM_COLOR: always + CARGO_TERM_COLOR: always jobs: - live: - name: goerli live tests - runs-on: ubuntu-latest - env: - GOERLI_RPC_URL: https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161 - ETHERSCAN_API_KEY: ${{ secrets.ETHERSCAN_API_KEY }} - TEST_PRIVATE_KEY: ${{ secrets.TEST_PRIVATE_KEY }} - steps: - - name: Checkout sources - uses: actions/checkout@v2 - - name: Install toolchain - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - profile: minimal - override: true - - uses: Swatinem/rust-cache@v1 - with: - cache-on-failure: true + live: + name: goerli live tests + runs-on: ubuntu-latest + env: + GOERLI_RPC_URL: https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161 + ETHERSCAN_API_KEY: ${{ secrets.ETHERSCAN_API_KEY }} + TEST_PRIVATE_KEY: ${{ secrets.TEST_PRIVATE_KEY }} + steps: + - name: Checkout sources + uses: actions/checkout@v2 + - name: Install toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + profile: minimal + override: true + - uses: Swatinem/rust-cache@v1 + with: + cache-on-failure: true - - name: cargo test - run: cargo test --package foundry-cli --test it -- verify::test_live_can_deploy_and_verify --exact --nocapture \ No newline at end of file + - name: cargo test + run: cargo test --package foundry-cli --test it -- verify::test_live_can_deploy_and_verify --exact --nocapture diff --git a/.github/workflows/project.yml b/.github/workflows/project.yml index 7394dc004b19..f1dfd2727bb5 100644 --- a/.github/workflows/project.yml +++ b/.github/workflows/project.yml @@ -1,16 +1,15 @@ name: project on: - issues: - types: [opened, transferred] + issues: + types: [opened, transferred] jobs: - add-to-project: - name: add issue - runs-on: ubuntu-latest - timeout-minutes: 60 - steps: - - uses: actions/add-to-project@main - with: - project-url: https://github.com/orgs/foundry-rs/projects/2 - github-token: ${{ secrets.GH_PROJECTS_TOKEN }} - + add-to-project: + name: add issue + runs-on: ubuntu-latest + timeout-minutes: 60 + steps: + - uses: actions/add-to-project@main + with: + project-url: https://github.com/orgs/foundry-rs/projects/2 + github-token: ${{ secrets.GH_PROJECTS_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 84d5fadc63a3..f60c9c3f88e0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,237 +1,237 @@ name: Release version on: - push: - tags: - - 'v*.*.*' - schedule: - - cron: '0 0 * * *' - workflow_dispatch: + push: + tags: + - "v*.*.*" + schedule: + - cron: "0 0 * * *" + workflow_dispatch: env: - IS_NIGHTLY: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} - CARGO_TERM_COLOR: always + IS_NIGHTLY: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} + CARGO_TERM_COLOR: always jobs: - prepare: - name: Prepare release - runs-on: ubuntu-latest - - outputs: - tag_name: ${{ steps.release_info.outputs.tag_name }} - release_name: ${{ steps.release_info.outputs.release_name }} - changelog: ${{ steps.build_changelog.outputs.changelog }} - - steps: - - name: Checkout sources - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - - name: Compute release name and tag - id: release_info - run: | - if [[ $IS_NIGHTLY ]]; then - echo "::set-output name=tag_name::nightly-${GITHUB_SHA}" - echo "::set-output name=release_name::Nightly ($(date '+%Y-%m-%d'))" - else - echo "::set-output name=tag_name::${GITHUB_REF_NAME}" - echo "::set-output name=release_name::${GITHUB_REF_NAME}" - fi - - # Creates a `nightly-SHA` tag for this specific nightly - # This tag is used for this specific nightly version's release - # which allows users to roll back. It is also used to build - # the changelog. - - name: Create build-specific nightly tag - if: ${{ env.IS_NIGHTLY }} - uses: actions/github-script@v5 - env: - TAG_NAME: ${{ steps.release_info.outputs.tag_name }} - with: - script: | - const createTag = require('./.github/scripts/create-tag.js') - await createTag({ github, context }, process.env.TAG_NAME) - - - name: Build changelog - id: build_changelog - uses: mikepenz/release-changelog-builder-action@v2 - with: - configuration: "./.github/changelog.json" - fromTag: ${{ env.IS_NIGHTLY && 'nightly' || '' }} - toTag: ${{ steps.release_info.outputs.tag_name }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - release-docker: - name: Release Docker - uses: ./.github/workflows/docker-publish.yml - - release: - name: ${{ matrix.job.target }} (${{ matrix.job.os }}) - runs-on: ${{ matrix.job.os }} - needs: prepare - strategy: - matrix: - job: - # The OS is used for the runner - # The platform is a generic platform name - # The target is used by Cargo - # The arch is either 386, arm64 or amd64 - # The svm target platform to use for the binary https://github.com/roynalnaruto/svm-rs/blob/84cbe0ac705becabdc13168bae28a45ad2299749/svm-builds/build.rs#L4-L24 - - os: ubuntu-latest - platform: linux - target: x86_64-unknown-linux-gnu - arch: amd64 - svm_target_platform: linux-amd64 - - os: ubuntu-latest - platform: linux - target: aarch64-unknown-linux-gnu - arch: arm64 - svm_target_platform: linux-aarch64 - - os: macos-latest - platform: darwin - target: x86_64-apple-darwin - arch: amd64 - svm_target_platform: macosx-amd64 - - os: macos-latest - platform: darwin - target: aarch64-apple-darwin - arch: arm64 - svm_target_platform: macosx-aarch64 - - os: windows-latest - platform: win32 - target: x86_64-pc-windows-msvc - arch: amd64 - svm_target_platform: windows-amd64 - - steps: - - name: Checkout sources - uses: actions/checkout@v2 - - - name: Install toolchain - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - target: ${{ matrix.job.target }} - override: true - - - uses: Swatinem/rust-cache@v1 - with: - cache-on-failure: true - - - name: Apple M1 setup - if: ${{ matrix.job.target == 'aarch64-apple-darwin' }} - run: | - echo "SDKROOT=$(xcrun -sdk macosx --show-sdk-path)" >> $GITHUB_ENV - echo "MACOSX_DEPLOYMENT_TARGET=$(xcrun -sdk macosx --show-sdk-platform-version)" >> $GITHUB_ENV - - - name: Linux ARM setup - if: ${{ matrix.job.target == 'aarch64-unknown-linux-gnu' }} - run: | - sudo apt-get update -y - sudo apt-get install -y gcc-aarch64-linux-gnu - echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV - - - name: Build binaries - uses: actions-rs/cargo@v1 - env: - SVM_TARGET_PLATFORM: ${{ matrix.job.svm_target_platform }} - with: - command: build - args: --release --bins --target ${{ matrix.job.target }} - - - name: Archive binaries - id: artifacts - env: - PLATFORM_NAME: ${{ matrix.job.platform }} - TARGET: ${{ matrix.job.target }} - ARCH: ${{ matrix.job.arch }} - VERSION_NAME: ${{ (env.IS_NIGHTLY && 'nightly') || needs.prepare.outputs.tag_name }} - run: | - if [ "$PLATFORM_NAME" == "linux" ]; then - tar -czvf "foundry_${VERSION_NAME}_${PLATFORM_NAME}_${ARCH}.tar.gz" -C ./target/${TARGET}/release forge cast anvil - echo "::set-output name=file_name::foundry_${VERSION_NAME}_${PLATFORM_NAME}_${ARCH}.tar.gz" - elif [ "$PLATFORM_NAME" == "darwin" ]; then - # We need to use gtar here otherwise the archive is corrupt. - # See: https://github.com/actions/virtual-environments/issues/2619 - gtar -czvf "foundry_${VERSION_NAME}_${PLATFORM_NAME}_${ARCH}.tar.gz" -C ./target/${TARGET}/release forge cast anvil - echo "::set-output name=file_name::foundry_${VERSION_NAME}_${PLATFORM_NAME}_${ARCH}.tar.gz" - else - cd ./target/${TARGET}/release - 7z a -tzip "foundry_${VERSION_NAME}_${PLATFORM_NAME}_${ARCH}.zip" forge.exe cast.exe anvil.exe - mv "foundry_${VERSION_NAME}_${PLATFORM_NAME}_${ARCH}.zip" ../../../ - echo "::set-output name=file_name::foundry_${VERSION_NAME}_${PLATFORM_NAME}_${ARCH}.zip" - fi - shell: bash - - - name: Build man page - id: man - if: ${{ matrix.job.target == 'x86_64-unknown-linux-gnu' }} - env: - PLATFORM_NAME: ${{ matrix.job.platform }} - TARGET: ${{ matrix.job.target }} - VERSION_NAME: ${{ (env.IS_NIGHTLY && 'nightly') || needs.prepare.outputs.tag_name }} - run: | - sudo apt-get -y install help2man - help2man -N ./target/${TARGET}/release/forge > forge.1 - help2man -N ./target/${TARGET}/release/cast > cast.1 - help2man -N ./target/${TARGET}/release/anvil > anvil.1 - gzip forge.1 - gzip cast.1 - gzip anvil.1 - tar -czvf "foundry_man_${VERSION_NAME}.tar.gz" forge.1.gz cast.1.gz anvil.1.gz - echo "::set-output name=foundry_man::foundry_man_${VERSION_NAME}.tar.gz" - shell: bash - - # Creates the release for this specific version - - name: Create release - uses: softprops/action-gh-release@v1 - with: - name: ${{ needs.prepare.outputs.release_name }} - tag_name: ${{ needs.prepare.outputs.tag_name }} - prerelease: ${{ env.IS_NIGHTLY }} - body: ${{ needs.prepare.outputs.changelog }} - files: | - ${{ steps.artifacts.outputs.file_name }} - ${{ steps.man.outputs.foundry_man }} - - # If this is a nightly release, it also updates the release - # tagged `nightly` for compatability with `foundryup` - - name: Update nightly release - if: ${{ env.IS_NIGHTLY }} - uses: softprops/action-gh-release@v1 - with: - name: 'Nightly' - tag_name: 'nightly' - prerelease: true - body: ${{ needs.prepare.outputs.changelog }} - files: | - ${{ steps.artifacts.outputs.file_name }} - ${{ steps.man.outputs.foundry_man }} - - cleanup: - name: Release cleanup - runs-on: ubuntu-latest - needs: release - - steps: - - name: Checkout sources - uses: actions/checkout@v2 - - # Moves the `nightly` tag to `HEAD` - - name: Move nightly tag - if: ${{ env.IS_NIGHTLY }} - uses: actions/github-script@v5 - with: - script: | - const moveTag = require('./.github/scripts/move-tag.js') - await moveTag({ github, context }, 'nightly') - - - name: Delete old nightlies - uses: actions/github-script@v5 - with: - script: | - const prunePrereleases = require('./.github/scripts/prune-prereleases.js') - await prunePrereleases({github, context}) + prepare: + name: Prepare release + runs-on: ubuntu-latest + + outputs: + tag_name: ${{ steps.release_info.outputs.tag_name }} + release_name: ${{ steps.release_info.outputs.release_name }} + changelog: ${{ steps.build_changelog.outputs.changelog }} + + steps: + - name: Checkout sources + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Compute release name and tag + id: release_info + run: | + if [[ $IS_NIGHTLY ]]; then + echo "::set-output name=tag_name::nightly-${GITHUB_SHA}" + echo "::set-output name=release_name::Nightly ($(date '+%Y-%m-%d'))" + else + echo "::set-output name=tag_name::${GITHUB_REF_NAME}" + echo "::set-output name=release_name::${GITHUB_REF_NAME}" + fi + + # Creates a `nightly-SHA` tag for this specific nightly + # This tag is used for this specific nightly version's release + # which allows users to roll back. It is also used to build + # the changelog. + - name: Create build-specific nightly tag + if: ${{ env.IS_NIGHTLY }} + uses: actions/github-script@v5 + env: + TAG_NAME: ${{ steps.release_info.outputs.tag_name }} + with: + script: | + const createTag = require('./.github/scripts/create-tag.js') + await createTag({ github, context }, process.env.TAG_NAME) + + - name: Build changelog + id: build_changelog + uses: mikepenz/release-changelog-builder-action@v2 + with: + configuration: "./.github/changelog.json" + fromTag: ${{ env.IS_NIGHTLY && 'nightly' || '' }} + toTag: ${{ steps.release_info.outputs.tag_name }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + release-docker: + name: Release Docker + uses: ./.github/workflows/docker-publish.yml + + release: + name: ${{ matrix.job.target }} (${{ matrix.job.os }}) + runs-on: ${{ matrix.job.os }} + needs: prepare + strategy: + matrix: + job: + # The OS is used for the runner + # The platform is a generic platform name + # The target is used by Cargo + # The arch is either 386, arm64 or amd64 + # The svm target platform to use for the binary https://github.com/roynalnaruto/svm-rs/blob/84cbe0ac705becabdc13168bae28a45ad2299749/svm-builds/build.rs#L4-L24 + - os: ubuntu-latest + platform: linux + target: x86_64-unknown-linux-gnu + arch: amd64 + svm_target_platform: linux-amd64 + - os: ubuntu-latest + platform: linux + target: aarch64-unknown-linux-gnu + arch: arm64 + svm_target_platform: linux-aarch64 + - os: macos-latest + platform: darwin + target: x86_64-apple-darwin + arch: amd64 + svm_target_platform: macosx-amd64 + - os: macos-latest + platform: darwin + target: aarch64-apple-darwin + arch: arm64 + svm_target_platform: macosx-aarch64 + - os: windows-latest + platform: win32 + target: x86_64-pc-windows-msvc + arch: amd64 + svm_target_platform: windows-amd64 + + steps: + - name: Checkout sources + uses: actions/checkout@v2 + + - name: Install toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + target: ${{ matrix.job.target }} + override: true + + - uses: Swatinem/rust-cache@v1 + with: + cache-on-failure: true + + - name: Apple M1 setup + if: ${{ matrix.job.target == 'aarch64-apple-darwin' }} + run: | + echo "SDKROOT=$(xcrun -sdk macosx --show-sdk-path)" >> $GITHUB_ENV + echo "MACOSX_DEPLOYMENT_TARGET=$(xcrun -sdk macosx --show-sdk-platform-version)" >> $GITHUB_ENV + + - name: Linux ARM setup + if: ${{ matrix.job.target == 'aarch64-unknown-linux-gnu' }} + run: | + sudo apt-get update -y + sudo apt-get install -y gcc-aarch64-linux-gnu + echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV + + - name: Build binaries + uses: actions-rs/cargo@v1 + env: + SVM_TARGET_PLATFORM: ${{ matrix.job.svm_target_platform }} + with: + command: build + args: --release --bins --target ${{ matrix.job.target }} + + - name: Archive binaries + id: artifacts + env: + PLATFORM_NAME: ${{ matrix.job.platform }} + TARGET: ${{ matrix.job.target }} + ARCH: ${{ matrix.job.arch }} + VERSION_NAME: ${{ (env.IS_NIGHTLY && 'nightly') || needs.prepare.outputs.tag_name }} + run: | + if [ "$PLATFORM_NAME" == "linux" ]; then + tar -czvf "foundry_${VERSION_NAME}_${PLATFORM_NAME}_${ARCH}.tar.gz" -C ./target/${TARGET}/release forge cast anvil + echo "::set-output name=file_name::foundry_${VERSION_NAME}_${PLATFORM_NAME}_${ARCH}.tar.gz" + elif [ "$PLATFORM_NAME" == "darwin" ]; then + # We need to use gtar here otherwise the archive is corrupt. + # See: https://github.com/actions/virtual-environments/issues/2619 + gtar -czvf "foundry_${VERSION_NAME}_${PLATFORM_NAME}_${ARCH}.tar.gz" -C ./target/${TARGET}/release forge cast anvil + echo "::set-output name=file_name::foundry_${VERSION_NAME}_${PLATFORM_NAME}_${ARCH}.tar.gz" + else + cd ./target/${TARGET}/release + 7z a -tzip "foundry_${VERSION_NAME}_${PLATFORM_NAME}_${ARCH}.zip" forge.exe cast.exe anvil.exe + mv "foundry_${VERSION_NAME}_${PLATFORM_NAME}_${ARCH}.zip" ../../../ + echo "::set-output name=file_name::foundry_${VERSION_NAME}_${PLATFORM_NAME}_${ARCH}.zip" + fi + shell: bash + + - name: Build man page + id: man + if: ${{ matrix.job.target == 'x86_64-unknown-linux-gnu' }} + env: + PLATFORM_NAME: ${{ matrix.job.platform }} + TARGET: ${{ matrix.job.target }} + VERSION_NAME: ${{ (env.IS_NIGHTLY && 'nightly') || needs.prepare.outputs.tag_name }} + run: | + sudo apt-get -y install help2man + help2man -N ./target/${TARGET}/release/forge > forge.1 + help2man -N ./target/${TARGET}/release/cast > cast.1 + help2man -N ./target/${TARGET}/release/anvil > anvil.1 + gzip forge.1 + gzip cast.1 + gzip anvil.1 + tar -czvf "foundry_man_${VERSION_NAME}.tar.gz" forge.1.gz cast.1.gz anvil.1.gz + echo "::set-output name=foundry_man::foundry_man_${VERSION_NAME}.tar.gz" + shell: bash + + # Creates the release for this specific version + - name: Create release + uses: softprops/action-gh-release@v1 + with: + name: ${{ needs.prepare.outputs.release_name }} + tag_name: ${{ needs.prepare.outputs.tag_name }} + prerelease: ${{ env.IS_NIGHTLY }} + body: ${{ needs.prepare.outputs.changelog }} + files: | + ${{ steps.artifacts.outputs.file_name }} + ${{ steps.man.outputs.foundry_man }} + + # If this is a nightly release, it also updates the release + # tagged `nightly` for compatability with `foundryup` + - name: Update nightly release + if: ${{ env.IS_NIGHTLY }} + uses: softprops/action-gh-release@v1 + with: + name: "Nightly" + tag_name: "nightly" + prerelease: true + body: ${{ needs.prepare.outputs.changelog }} + files: | + ${{ steps.artifacts.outputs.file_name }} + ${{ steps.man.outputs.foundry_man }} + + cleanup: + name: Release cleanup + runs-on: ubuntu-latest + needs: release + + steps: + - name: Checkout sources + uses: actions/checkout@v2 + + # Moves the `nightly` tag to `HEAD` + - name: Move nightly tag + if: ${{ env.IS_NIGHTLY }} + uses: actions/github-script@v5 + with: + script: | + const moveTag = require('./.github/scripts/move-tag.js') + await moveTag({ github, context }, 'nightly') + + - name: Delete old nightlies + uses: actions/github-script@v5 + with: + script: | + const prunePrereleases = require('./.github/scripts/prune-prereleases.js') + await prunePrereleases({github, context}) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 922a06c008b0..c5f8d91eeab1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,217 +1,217 @@ on: - push: - branches: - - master - pull_request: + push: + branches: + - master + pull_request: name: test env: - NEXTEST_EXPERIMENTAL_FILTER_EXPR: 1 - CARGO_TERM_COLOR: always + NEXTEST_EXPERIMENTAL_FILTER_EXPR: 1 + CARGO_TERM_COLOR: always jobs: - build-tests: - name: build tests / ${{ matrix.archive.name }} - runs-on: ubuntu-latest - strategy: - matrix: - archive: - - name: unit-tests - file: nextest-unit.tar.zst - flags: --workspace --all-features --lib --bins - - name: integration-tests - file: nextest-integration.tar.zst - flags: --workspace - - name: external-integration-tests - file: nextest-external-integration.tar.zst - flags: -p foundry-cli --features external-integration-tests - steps: - - name: Checkout sources - uses: actions/checkout@v2 - - name: Install toolchain - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - profile: minimal - override: true - - uses: Swatinem/rust-cache@v1 - with: - cache-on-failure: true - - name: Install nextest - uses: taiki-e/install-action@nextest - - - name: Build archive (unit tests) - run: cargo nextest archive --locked ${{ matrix.archive.flags }} --archive-file ${{ matrix.archive.file }} - - name: Upload archive - uses: actions/upload-artifact@v3 - with: - name: ${{ matrix.archive.name }} - path: ${{ matrix.archive.file }} - - unit: - name: unit tests / ${{ matrix.job.name }} - runs-on: ubuntu-latest - needs: build-tests - timeout-minutes: 60 - strategy: - matrix: - job: - - name: non-forking - filter: '!test(~fork) & !test(~live)' - - name: forking - filter: 'test(~fork) & !test(~live)' - env: - ETH_RPC_URL: https://eth-mainnet.alchemyapi.io/v2/C3JEvfW6VgtqZQa-Qp1E-2srEiIc02sD - steps: - - name: Checkout sources - uses: actions/checkout@v2 - - name: Install nextest - uses: taiki-e/install-action@nextest - - run: mkdir -p ~/.cargo/bin - - name: Download archives - uses: actions/download-artifact@v3 - with: - name: unit-tests - - - name: cargo nextest - run: ~/.cargo/bin/cargo-nextest nextest run --retries 3 --archive-file nextest-unit.tar.zst -E '${{ matrix.job.filter }}' - - integration: - name: integration tests / ${{ matrix.job.name }} - runs-on: ubuntu-latest - needs: build-tests - strategy: - matrix: - job: - - name: non-forking - filter: '!test(~fork) & !test(~live)' - - name: forking - filter: 'test(~fork) & !test(~live)' - partition: [1, 2] - env: - ETH_RPC_URL: https://eth-mainnet.alchemyapi.io/v2/C3JEvfW6VgtqZQa-Qp1E-2srEiIc02sD - steps: - - name: Checkout sources - uses: actions/checkout@v2 - - name: Install nextest - uses: taiki-e/install-action@nextest - - run: mkdir -p ~/.cargo/bin - - name: Download archives - uses: actions/download-artifact@v3 - with: - name: integration-tests - - - name: Forge RPC cache - uses: actions/cache@v3 - if: matrix.job.name != 'non-forking' - with: - path: "$HOME/.foundry/cache" - key: rpc-cache-${{ hashFiles('cli/tests/rpc-cache-keyfile') }} - - name: Setup git config - run: | - git config --global user.name "GitHub Actions Bot" - git config --global user.email "<>" - - - name: cargo nextest - run: ~/.cargo/bin/cargo-nextest nextest run --partition count:${{ matrix.partition }}/2 --retries 3 --archive-file nextest-integration.tar.zst -E '${{ matrix.job.filter }}' - - external-integration: - name: external integration tests / ${{ matrix.job.name }} - runs-on: ubuntu-latest - needs: build-tests - strategy: - matrix: - job: - - name: non-forking - filter: '!test(~fork_integration) & !test(~live)' - - name: forking - filter: 'test(~fork_integration) & !test(~live)' - env: - ETH_RPC_URL: https://eth-mainnet.alchemyapi.io/v2/C3JEvfW6VgtqZQa-Qp1E-2srEiIc02sD - steps: - - name: Checkout sources - uses: actions/checkout@v2 - - name: Install nextest - uses: taiki-e/install-action@nextest - - run: mkdir -p ~/.cargo/bin - - name: Download archives - uses: actions/download-artifact@v3 - with: - name: external-integration-tests - - - name: Forge RPC cache - uses: actions/cache@v3 - if: matrix.job.name != 'non-forking' - with: - path: "$HOME/.foundry/cache" - key: rpc-cache-${{ hashFiles('cli/tests/rpc-cache-keyfile') }} - - - name: Setup git config - run: | - git config --global user.name "GitHub Actions Bot" - git config --global user.email "<>" - - - name: Force use of HTTPS for submodules - run: git config --global url."https://github.com/".insteadOf "git@github.com:" - - - name: cargo nextest - run: ~/.cargo/bin/cargo-nextest nextest run --retries 3 --archive-file nextest-external-integration.tar.zst -E '${{ matrix.job.filter }}' - - doc: - name: doc tests - runs-on: ubuntu-latest - steps: - - name: Checkout sources - uses: actions/checkout@v2 - - name: Install toolchain - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - profile: minimal - override: true - - uses: Swatinem/rust-cache@v1 - with: - cache-on-failure: true - - - name: cargo test - run: cargo test --locked --workspace --all-features --doc - - lint: - runs-on: ubuntu-latest - steps: - - name: Checkout sources - uses: actions/checkout@v2 - - - name: Install toolchain - uses: actions-rs/toolchain@v1 - with: - toolchain: nightly - profile: minimal - components: rustfmt, clippy - override: true - - - uses: Swatinem/rust-cache@v1 - with: - cache-on-failure: true - - - name: cargo fmt - uses: actions-rs/cargo@v1 - with: - command: fmt - args: --all --check - - - name: cargo clippy - uses: actions-rs/clippy-check@v1 - with: - args: --all --all-features -- -D warnings - token: ${{ secrets.GITHUB_TOKEN }} - - - name: forge fmt - run: cargo run --bin forge -- fmt --check testdata/ - - cross-platform: - name: Cross-platform tests - if: github.event_name != 'pull_request' - needs: [ integration, lint, doc, unit ] - uses: ./.github/workflows/cross-platform.yml + build-tests: + name: build tests / ${{ matrix.archive.name }} + runs-on: ubuntu-latest + strategy: + matrix: + archive: + - name: unit-tests + file: nextest-unit.tar.zst + flags: --workspace --all-features --lib --bins + - name: integration-tests + file: nextest-integration.tar.zst + flags: --workspace + - name: external-integration-tests + file: nextest-external-integration.tar.zst + flags: -p foundry-cli --features external-integration-tests + steps: + - name: Checkout sources + uses: actions/checkout@v2 + - name: Install toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + profile: minimal + override: true + - uses: Swatinem/rust-cache@v1 + with: + cache-on-failure: true + - name: Install nextest + uses: taiki-e/install-action@nextest + + - name: Build archive (unit tests) + run: cargo nextest archive --locked ${{ matrix.archive.flags }} --archive-file ${{ matrix.archive.file }} + - name: Upload archive + uses: actions/upload-artifact@v3 + with: + name: ${{ matrix.archive.name }} + path: ${{ matrix.archive.file }} + + unit: + name: unit tests / ${{ matrix.job.name }} + runs-on: ubuntu-latest + needs: build-tests + timeout-minutes: 60 + strategy: + matrix: + job: + - name: non-forking + filter: "!test(~fork) & !test(~live)" + - name: forking + filter: "test(~fork) & !test(~live)" + env: + ETH_RPC_URL: https://eth-mainnet.alchemyapi.io/v2/C3JEvfW6VgtqZQa-Qp1E-2srEiIc02sD + steps: + - name: Checkout sources + uses: actions/checkout@v2 + - name: Install nextest + uses: taiki-e/install-action@nextest + - run: mkdir -p ~/.cargo/bin + - name: Download archives + uses: actions/download-artifact@v3 + with: + name: unit-tests + + - name: cargo nextest + run: ~/.cargo/bin/cargo-nextest nextest run --retries 3 --archive-file nextest-unit.tar.zst -E '${{ matrix.job.filter }}' + + integration: + name: integration tests / ${{ matrix.job.name }} + runs-on: ubuntu-latest + needs: build-tests + strategy: + matrix: + job: + - name: non-forking + filter: "!test(~fork) & !test(~live)" + - name: forking + filter: "test(~fork) & !test(~live)" + partition: [1, 2] + env: + ETH_RPC_URL: https://eth-mainnet.alchemyapi.io/v2/C3JEvfW6VgtqZQa-Qp1E-2srEiIc02sD + steps: + - name: Checkout sources + uses: actions/checkout@v2 + - name: Install nextest + uses: taiki-e/install-action@nextest + - run: mkdir -p ~/.cargo/bin + - name: Download archives + uses: actions/download-artifact@v3 + with: + name: integration-tests + + - name: Forge RPC cache + uses: actions/cache@v3 + if: matrix.job.name != 'non-forking' + with: + path: "$HOME/.foundry/cache" + key: rpc-cache-${{ hashFiles('cli/tests/rpc-cache-keyfile') }} + - name: Setup git config + run: | + git config --global user.name "GitHub Actions Bot" + git config --global user.email "<>" + + - name: cargo nextest + run: ~/.cargo/bin/cargo-nextest nextest run --partition count:${{ matrix.partition }}/2 --retries 3 --archive-file nextest-integration.tar.zst -E '${{ matrix.job.filter }}' + + external-integration: + name: external integration tests / ${{ matrix.job.name }} + runs-on: ubuntu-latest + needs: build-tests + strategy: + matrix: + job: + - name: non-forking + filter: "!test(~fork_integration) & !test(~live)" + - name: forking + filter: "test(~fork_integration) & !test(~live)" + env: + ETH_RPC_URL: https://eth-mainnet.alchemyapi.io/v2/C3JEvfW6VgtqZQa-Qp1E-2srEiIc02sD + steps: + - name: Checkout sources + uses: actions/checkout@v2 + - name: Install nextest + uses: taiki-e/install-action@nextest + - run: mkdir -p ~/.cargo/bin + - name: Download archives + uses: actions/download-artifact@v3 + with: + name: external-integration-tests + + - name: Forge RPC cache + uses: actions/cache@v3 + if: matrix.job.name != 'non-forking' + with: + path: "$HOME/.foundry/cache" + key: rpc-cache-${{ hashFiles('cli/tests/rpc-cache-keyfile') }} + + - name: Setup git config + run: | + git config --global user.name "GitHub Actions Bot" + git config --global user.email "<>" + + - name: Force use of HTTPS for submodules + run: git config --global url."https://github.com/".insteadOf "git@github.com:" + + - name: cargo nextest + run: ~/.cargo/bin/cargo-nextest nextest run --retries 3 --archive-file nextest-external-integration.tar.zst -E '${{ matrix.job.filter }}' + + doc: + name: doc tests + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v2 + - name: Install toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + profile: minimal + override: true + - uses: Swatinem/rust-cache@v1 + with: + cache-on-failure: true + + - name: cargo test + run: cargo test --locked --workspace --all-features --doc + + lint: + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v2 + + - name: Install toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: nightly + profile: minimal + components: rustfmt, clippy + override: true + + - uses: Swatinem/rust-cache@v1 + with: + cache-on-failure: true + + - name: cargo fmt + uses: actions-rs/cargo@v1 + with: + command: fmt + args: --all --check + + - name: cargo clippy + uses: actions-rs/clippy-check@v1 + with: + args: --all --all-features -- -D warnings + token: ${{ secrets.GITHUB_TOKEN }} + + - name: forge fmt + run: cargo run --bin forge -- fmt --check testdata/ + + cross-platform: + name: Cross-platform tests + if: github.event_name != 'pull_request' + needs: [integration, lint, doc, unit] + uses: ./.github/workflows/cross-platform.yml diff --git a/.gitignore b/.gitignore index 7d01162685a5..3f8d7ea3f9ea 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,4 @@ /target out/ out.json -.idea \ No newline at end of file +.idea diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9523178d86a4..5be14446a7c0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -37,8 +37,8 @@ around bugs and participate in reviewing PRs. If you have reviewed existing documentation and still have questions, or you are having problems, you can get help in the following ways: -- **Asking in the support Telegram:** The [Foundry Support Telegram][support-tg] is a fast and easy way to ask questions. -- **Opening a discussion:** This repository comes with a discussions board where you can also ask for help. Click the "Discussions" tab in the top. +- **Asking in the support Telegram:** The [Foundry Support Telegram][support-tg] is a fast and easy way to ask questions. +- **Opening a discussion:** This repository comes with a discussions board where you can also ask for help. Click the "Discussions" tab in the top. As Foundry is still in heavy development, the documentation can be a bit scattered. The [Foundry Book][foundry-book] is our current best-effort attempt at keeping up-to-date information. @@ -52,10 +52,10 @@ just fill in what you can. Contributors will ask follow up questions if somethin The most important pieces of information we need in a bug report are: -- The Foundry version you are on (and that it is up to date) -- The platform you are on (Windows, macOS, an M1 Mac or Linux) -- Code snippets if this is happening in relation to testing or building code -- Concrete steps to reproduce the bug +- The Foundry version you are on (and that it is up to date) +- The platform you are on (Windows, macOS, an M1 Mac or Linux) +- Code snippets if this is happening in relation to testing or building code +- Concrete steps to reproduce the bug In order to rule out the possibility of the bug being in your project, the code snippets should be as minimal as possible. It is better if you can reproduce the bug with a small snippet as opposed to an entire project! @@ -109,11 +109,11 @@ in the future. Types of tests include: -- **Unit tests**: Functions which have very specific tasks should be unit tested. -- **Integration tests**: For general purpose, far reaching functionality, integration tests should be added. - The best way to add a new integration test is to look at existing ones and follow the style. +- **Unit tests**: Functions which have very specific tasks should be unit tested. +- **Integration tests**: For general purpose, far reaching functionality, integration tests should be added. + The best way to add a new integration test is to look at existing ones and follow the style. -Tests that use forking must contain "fork" in their name. +Tests that use forking must contain "fork" in their name. #### Commits @@ -138,7 +138,7 @@ Keep an eye out for comments from code owners to provide guidance on conflicting **Any Foundry community member is welcome to review any pull request**. -All contributors who choose to review and provide feedback on pull requests have a responsibility to both the project and individual making the contribution. Reviews and feedback must be helpful, insightful, and geared towards improving the contribution as opposed to simply blocking it. If there are reasons why you feel the PR should not be merged, explain what those are. Do not expect to be able to block a PR from advancing simply because you say "no" without giving an explanation. Be open to having your mind changed. Be open to working *with* the contributor to make the pull request better. +All contributors who choose to review and provide feedback on pull requests have a responsibility to both the project and individual making the contribution. Reviews and feedback must be helpful, insightful, and geared towards improving the contribution as opposed to simply blocking it. If there are reasons why you feel the PR should not be merged, explain what those are. Do not expect to be able to block a PR from advancing simply because you say "no" without giving an explanation. Be open to having your mind changed. Be open to working _with_ the contributor to make the pull request better. Reviews that are dismissive or disrespectful of the contributor or any other reviewers are strictly counter to the Code of Conduct. @@ -159,7 +159,7 @@ Focus first on the most significant aspects of the change: Note that only **incremental** improvement is needed to land a PR. This means that the PR does not need to be perfect, only better than the status quo. Follow-up PRs may be opened to continue iterating. -When changes are necessary, *request* them, do not *demand* them, and **do not assume that the submitter already knows how to add a test or run a benchmark**. +When changes are necessary, _request_ them, do not _demand_ them, and **do not assume that the submitter already knows how to add a test or run a benchmark**. Specific performance optimization techniques, coding styles and conventions change over time. The first impression you give to a new contributor never does. @@ -171,7 +171,7 @@ If your comments were addressed but were not folded after new commits, or if the ##### Be aware of the person behind the code -Be aware that *how* you communicate requests and reviews in your feedback can have a significant impact on the success of the pull request. Yes, we may merge a particular change that makes Foundry better, but the individual might just not want to have anything to do with Foundry ever again. The goal is not just having good code. +Be aware that _how_ you communicate requests and reviews in your feedback can have a significant impact on the success of the pull request. Yes, we may merge a particular change that makes Foundry better, but the individual might just not want to have anything to do with Foundry ever again. The goal is not just having good code. ##### Abandoned or stale pull requests diff --git a/Cargo.toml b/Cargo.toml index 19c9e839724e..46ddf0f58c82 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,16 +22,18 @@ members = [ # and we don't rely on it for debugging that much debug = 0 -[profile.dev.package] # These speed up local tests -ethers-solc.opt-level = 3 -revm.opt-level = 3 +[profile.dev.package.ethers-solc] +opt-level = 3 + +[profile.dev.package.revm] +opt-level = 3 -[profile.test.package] -# These will speed up all forge script related integration tests -axum.opt-level = 3 +# These speed up all forge script related integration tests +[profile.test.package.axum] +opt-level = 3 -# local "release" mode +# Local "release" mode, more optimized than dev but much faster to compile than release [profile.local] inherits = "dev" opt-level = 3 @@ -42,27 +44,26 @@ panic = 'unwind' incremental = true codegen-units = 16 - [profile.release] # Optimize for binary size, but keep loop vectorization opt-level = "s" -strip = true # Performance optimizations lto = "fat" -codegen-units = 1 -panic = "abort" -# We end up stripping away these symbols anyway debug = 0 +strip = true +panic = "abort" +codegen-units = 1 -## Patch ethers-rs with a local checkout then run `cargo update -p ethers` -#[patch."https://github.com/gakonst/ethers-rs"] -#ethers = { path = "../ethers-rs" } -#ethers-core = { path = "../ethers-rs/ethers-core" } -#ethers-contract = { path = "../ethers-rs/ethers-contract" } -#ethers-providers = { path = "../ethers-rs/ethers-providers" } -#ethers-signers = { path = "../ethers-rs/ethers-signers" } -#ethers-etherscan = { path = "../ethers-rs/ethers-etherscan" } -#ethers-solc = { path = "../ethers-rs/ethers-solc" } +# # Patch ethers-rs with a local checkout then run `cargo update -p ethers` +# [patch."https://github.com/gakonst/ethers-rs"] +# ethers = { path = "../ethers-rs" } +# ethers-addressbook = { path = "../ethers-rs/ethers-addressbook" } +# ethers-core = { path = "../ethers-rs/ethers-core" } +# ethers-contract = { path = "../ethers-rs/ethers-contract" } +# ethers-providers = { path = "../ethers-rs/ethers-providers" } +# ethers-signers = { path = "../ethers-rs/ethers-signers" } +# ethers-etherscan = { path = "../ethers-rs/ethers-etherscan" } +# ethers-solc = { path = "../ethers-rs/ethers-solc" } -[patch.crates-io] -#revm = { path = "../revm/crates/revm" } \ No newline at end of file +# [patch.crates-io] +# revm = { path = "../revm/crates/revm" } diff --git a/Dockerfile b/Dockerfile index b59377b863d8..4f2dbefb51f9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -from alpine as build-environment +FROM alpine AS build-environment WORKDIR /opt RUN apk add clang lld curl build-base linux-headers git \ && curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup.sh \ @@ -11,7 +11,7 @@ RUN source $HOME/.profile && cargo build --release \ && strip /opt/foundry/target/release/cast \ && strip /opt/foundry/target/release/anvil -from alpine as foundry-client +FROM alpine AS foundry-client ENV GLIBC_KEY=https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub ENV GLIBC_KEY_FILE=/etc/apk/keys/sgerrand.rsa.pub ENV GLIBC_RELEASE=https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.35-r0/glibc-2.35-r0.apk @@ -24,4 +24,4 @@ COPY --from=build-environment /opt/foundry/target/release/forge /usr/local/bin/f COPY --from=build-environment /opt/foundry/target/release/cast /usr/local/bin/cast COPY --from=build-environment /opt/foundry/target/release/anvil /usr/local/bin/anvil RUN adduser -Du 1000 foundry -ENTRYPOINT ["/bin/sh", "-c"] \ No newline at end of file +ENTRYPOINT ["/bin/sh", "-c"] diff --git a/LICENSE-APACHE b/LICENSE-APACHE index d40ba5d76675..3c4dfe081ce4 100644 --- a/LICENSE-APACHE +++ b/LICENSE-APACHE @@ -1,203 +1,187 @@ -Copyright (c) 2021 Georgios Konstantopoulos - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. diff --git a/LICENSE-MIT b/LICENSE-MIT index b2e52c762427..8dce0ba55e1c 100644 --- a/LICENSE-MIT +++ b/LICENSE-MIT @@ -1,25 +1,19 @@ Copyright (c) 2021 Georgios Konstantopoulos -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE O THE USE OR OTHER -DEALINGS IN THE SOFTWARE.R +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 2e160ab50438..14c708ba65d6 100644 --- a/README.md +++ b/README.md @@ -14,9 +14,9 @@ Foundry consists of: -- [**Forge**](./forge): Ethereum testing framework (like Truffle, Hardhat and DappTools). -- [**Cast**](./cast): Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data. -- [**Anvil**](./anvil): local Ethereum node, akin to Ganache, Hardhat Network. +- [**Forge**](./forge): Ethereum testing framework (like Truffle, Hardhat and DappTools). +- [**Cast**](./cast): Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data. +- [**Anvil**](./anvil): local Ethereum node, akin to Ganache, Hardhat Network. **Need help getting started with Foundry? Read the [📖 Foundry Book][foundry-book] (WIP)!** @@ -77,19 +77,19 @@ You can manually download nightly releases [here](https://github.com/foundry-rs/ ### Features -- **Fast & flexible compilation pipeline** - - Automatic Solidity compiler version detection & installation (under `~/.svm`) - - **Incremental compilation & caching**: Only changed files are re-compiled - - Parallel compilation - - Non-standard directory structures support (e.g. [Hardhat repos](https://twitter.com/gakonst/status/1461289225337421829)) -- **Tests are written in Solidity** (like in DappTools) -- **Fast fuzz testing** with shrinking of inputs & printing of counter-examples -- **Fast remote RPC forking mode**, leveraging Rust's async infrastructure like tokio -- **Flexible debug logging** - - DappTools-style, using `DsTest`'s emitted logs - - Hardhat-style, using the popular `console.sol` contract -- **Portable (5-10MB) & easy to install** without requiring Nix or any other package manager -- **Fast CI** with the [Foundry GitHub action][foundry-gha]. +- **Fast & flexible compilation pipeline** + - Automatic Solidity compiler version detection & installation (under `~/.svm`) + - **Incremental compilation & caching**: Only changed files are re-compiled + - Parallel compilation + - Non-standard directory structures support (e.g. [Hardhat repos](https://twitter.com/gakonst/status/1461289225337421829)) +- **Tests are written in Solidity** (like in DappTools) +- **Fast fuzz testing** with shrinking of inputs & printing of counter-examples +- **Fast remote RPC forking mode**, leveraging Rust's async infrastructure like tokio +- **Flexible debug logging** + - DappTools-style, using `DsTest`'s emitted logs + - Hardhat-style, using the popular `console.sol` contract +- **Portable (5-10MB) & easy to install** without requiring Nix or any other package manager +- **Fast CI** with the [Foundry GitHub action][foundry-gha]. ### How Fast? @@ -143,8 +143,8 @@ You can re-use your `.dapprc` environment variabless by running `source .dapprc` You can find additional setup and configurations guides in the [Foundry Book][foundry-book]: -- [Setting up VSCode][vscode-setup] -- [Shell autocompletions][shell-setup] +- [Setting up VSCode][vscode-setup] +- [Shell autocompletions][shell-setup] ### Troubleshooting Installation @@ -185,19 +185,19 @@ First, see if the answer to your question can be found in [book][foundry-book], If the answer is not there: -- Join the [support Telegram][tg-support-url] to get help, or -- Open a [discussion](https://github.com/foundry-rs/foundry/discussions/new) with your question, or -- Open an issue with [the bug](https://github.com/foundry-rs/foundry/issues/new) +- Join the [support Telegram][tg-support-url] to get help, or +- Open a [discussion](https://github.com/foundry-rs/foundry/discussions/new) with your question, or +- Open an issue with [the bug](https://github.com/foundry-rs/foundry/issues/new) If you want to contribute, or follow along with contributor discussion, you can use our [main telegram](https://t.me/foundry_rs) to chat with us about the development of Foundry! ## Acknowledgements -- Foundry is a clean-room rewrite of the testing framework [DappTools](https://github.com/dapphub/dapptools). None of this would have been possible without the DappHub team's work over the years. -- [Matthias Seitz](https://twitter.com/mattsse_): Created [ethers-solc](https://github.com/gakonst/ethers-rs/tree/master/ethers-solc/) which is the backbone of our compilation pipeline, as well as countless contributions to ethers, in particular the `abigen` macros. -- [Rohit Narurkar](https://twitter.com/rohitnarurkar): Created the Rust Solidity version manager [svm-rs](https://github.com/roynalnaruto/svm-rs) which we use to auto-detect and manage multiple Solidity versions. -- [Brock Elmore](https://twitter.com/brockjelmore): For extending the VM's cheatcodes and implementing [structured call tracing](https://github.com/foundry-rs/foundry/pull/192), a critical feature for debugging smart contract calls. -- All the other [contributors](https://github.com/foundry-rs/foundry/graphs/contributors) to the [ethers-rs](https://github.com/gakonst/ethers-rs) & [foundry](https://github.com/foundry-rs/foundry) repositories and chatrooms. +- Foundry is a clean-room rewrite of the testing framework [DappTools](https://github.com/dapphub/dapptools). None of this would have been possible without the DappHub team's work over the years. +- [Matthias Seitz](https://twitter.com/mattsse_): Created [ethers-solc](https://github.com/gakonst/ethers-rs/tree/master/ethers-solc/) which is the backbone of our compilation pipeline, as well as countless contributions to ethers, in particular the `abigen` macros. +- [Rohit Narurkar](https://twitter.com/rohitnarurkar): Created the Rust Solidity version manager [svm-rs](https://github.com/roynalnaruto/svm-rs) which we use to auto-detect and manage multiple Solidity versions. +- [Brock Elmore](https://twitter.com/brockjelmore): For extending the VM's cheatcodes and implementing [structured call tracing](https://github.com/foundry-rs/foundry/pull/192), a critical feature for debugging smart contract calls. +- All the other [contributors](https://github.com/foundry-rs/foundry/graphs/contributors) to the [ethers-rs](https://github.com/gakonst/ethers-rs) & [foundry](https://github.com/foundry-rs/foundry) repositories and chatrooms. [foundry-book]: https://book.getfoundry.sh [foundry-gha]: https://github.com/foundry-rs/foundry-toolchain diff --git a/anvil/Cargo.toml b/anvil/Cargo.toml index da3de17dcc82..a1c23bbcfd42 100644 --- a/anvil/Cargo.toml +++ b/anvil/Cargo.toml @@ -4,9 +4,7 @@ version = "0.1.0" edition = "2021" license = "MIT OR Apache-2.0" readme = "README.md" -description = """ -foundry's local ethereum node -""" +description = "Foundry's local ethereum node" [[bin]] name = "anvil" @@ -15,11 +13,7 @@ required-features = ["cli"] [build-dependencies] # used to generate constants -vergen = { version = "7.0", default-features = false, features = [ - "build", - "rustc", - "git", -] } +vergen = { version = "7.0", default-features = false, features = ["build", "rustc", "git"] } [dependencies] # foundry internal @@ -63,12 +57,8 @@ yansi = "0.5.1" tempfile = "3.3.0" # cli -clap = { version = "3.0.10", features = [ - "derive", - "env", - "wrap_help", -], optional = true } -clap_complete = { version = "3.0.4", optional = true } +clap = { version = "3.0.10", features = ["derive", "env", "wrap_help"], optional = true } +clap_complete = { version = "3.0.4", optional = true } chrono = "0.4.19" auto_impl = "0.5.0" ctrlc = { version = "3", optional = true } diff --git a/anvil/README.md b/anvil/README.md index 8be694ba85e4..3c391445e2a4 100644 --- a/anvil/README.md +++ b/anvil/README.md @@ -4,12 +4,12 @@ ## Features -* Network forking: fork any EVM-compatible blockchain, same as in `forge` -* [Ethereum JSON-RPC](https://eth.wiki/json-rpc/API) support -* Additional JSON-RPC endpoints, compatible with ganache and hardhat - * snapshot/revert state - * mining modes: auto, interval, manual, none - * ... +- Network forking: fork any EVM-compatible blockchain, same as in `forge` +- [Ethereum JSON-RPC](https://eth.wiki/json-rpc/API) support +- Additional JSON-RPC endpoints, compatible with ganache and hardhat + - snapshot/revert state + - mining modes: auto, interval, manual, none + - ... ## Installation @@ -26,7 +26,7 @@ cargo install --path ./anvil --bins --locked --force ## Getting started ```console -anvil +anvil _ _ (_) | | @@ -83,4 +83,3 @@ Gas Limit Listening on 127.0.0.1:8545 ``` - diff --git a/anvil/core/Cargo.toml b/anvil/core/Cargo.toml index 9dfb0e354a4b..57289b3d8564 100644 --- a/anvil/core/Cargo.toml +++ b/anvil/core/Cargo.toml @@ -7,7 +7,12 @@ license = "MIT OR Apache-2.0" [dependencies] # foundry internal foundry-evm = { path = "../../evm" } -revm = { version = "2.1", default-features = false, features = ["std", "k256", "with-serde", "memory_limit"] } +revm = { version = "2.1", default-features = false, features = [ + "std", + "k256", + "with-serde", + "memory_limit", +] } ethers-core = { git = "https://github.com/gakonst/ethers-rs", default-features = false } serde = { version = "1.0", features = ["derive"] } diff --git a/anvil/rpc/Cargo.toml b/anvil/rpc/Cargo.toml index 6e96f12b3ed4..d4e4536ed85c 100644 --- a/anvil/rpc/Cargo.toml +++ b/anvil/rpc/Cargo.toml @@ -3,9 +3,7 @@ name = "anvil-rpc" version = "0.1.0" edition = "2021" license = "MIT OR Apache-2.0" -description = """ -RPC support -""" +description = "RPC support" [dependencies] serde = { version = "1.0", features = ["derive"] } diff --git a/anvil/server/Cargo.toml b/anvil/server/Cargo.toml index cec076139b4d..1a53c90d6494 100644 --- a/anvil/server/Cargo.toml +++ b/anvil/server/Cargo.toml @@ -3,9 +3,7 @@ name = "anvil-server" version = "0.1.0" edition = "2021" license = "MIT OR Apache-2.0" -description = """ -Customizable RPC server -""" +description = "Customizable RPC server" [dependencies] anvil-rpc = { path = "../rpc" } @@ -24,7 +22,7 @@ futures = "0.3" # ipc parity-tokio-ipc = { version = "0.9.0", optional = true } -bytes = { version = "1.2" , optional = true } +bytes = { version = "1.2", optional = true } tokio-util = { version = "0.7.4", features = ["codec"], optional = true } # misc @@ -33,13 +31,9 @@ serde = { version = "1.0.136", features = ["derive"] } async-trait = "0.1.53" thiserror = "1.0.34" -clap = { version = "3.0.10", features = [ - "derive", - "env", -], optional = true } +clap = { version = "3.0.10", features = ["derive", "env"], optional = true } pin-project = "1.0.12" - [features] default = ["ipc"] ipc = ["parity-tokio-ipc", "bytes", "tokio-util"] diff --git a/binder/Cargo.toml b/binder/Cargo.toml index 9a6773db6e76..29ab0754369d 100644 --- a/binder/Cargo.toml +++ b/binder/Cargo.toml @@ -4,17 +4,20 @@ version = "0.1.0" edition = "2021" license = "MIT OR Apache-2.0" readme = "./README.md" -description = """ -Generate rust bindings for solidity projects -""" +description = "Generate rust bindings for solidity projects" repository = "https://github.com/foundry-rs/foundry" keywords = ["ethereum", "web3", "solidity"] - [dependencies] foundry-config = { path = "../config" } -ethers-solc = { git = "https://github.com/gakonst/ethers-rs", default-features = false, features = ["async", "svm-solc", "project-util"] } -ethers-contract = { git = "https://github.com/gakonst/ethers-rs", default-features = false, features = ["abigen"] } +ethers-solc = { git = "https://github.com/gakonst/ethers-rs", default-features = false, features = [ + "async", + "svm-solc", + "project-util", +] } +ethers-contract = { git = "https://github.com/gakonst/ethers-rs", default-features = false, features = [ + "abigen", +] } curl = { version = "0.4", default-features = false, features = ["http2"] } eyre = "0.6" git2 = { version = "0.15.0", default-features = false } diff --git a/binder/README.md b/binder/README.md index 2699462f8002..077a78e4c7d7 100644 --- a/binder/README.md +++ b/binder/README.md @@ -39,4 +39,4 @@ fn main() { generate() } } -``` \ No newline at end of file +``` diff --git a/cast/Cargo.toml b/cast/Cargo.toml index 9f3f14c00bb5..5ff8023165ad 100644 --- a/cast/Cargo.toml +++ b/cast/Cargo.toml @@ -7,16 +7,17 @@ readme = "README.md" repository = "https://github.com/foundry-rs/foundry" keywords = ["ethereum", "web3"] - [dependencies] foundry-utils = { path = "../utils" } foundry-evm = { path = "./../evm" } foundry-config = { path = "./../config" } -foundry-common = {path = "./../common"} +foundry-common = { path = "./../common" } futures = "0.3.17" ethers-etherscan = { git = "https://github.com/gakonst/ethers-rs", default-features = false } -ethers-contract = { git = "https://github.com/gakonst/ethers-rs", default-features = false, features = ["abigen"] } +ethers-contract = { git = "https://github.com/gakonst/ethers-rs", default-features = false, features = [ + "abigen", +] } ethers-core = { git = "https://github.com/gakonst/ethers-rs", default-features = false } ethers-providers = { git = "https://github.com/gakonst/ethers-rs", default-features = false } ethers-signers = { git = "https://github.com/gakonst/ethers-rs", default-features = false } diff --git a/cast/README.md b/cast/README.md index a16c978ae181..61f6148b46bb 100644 --- a/cast/README.md +++ b/cast/README.md @@ -6,60 +6,60 @@ ## Features -- [x] `--abi-decode` -- [x] `--calldata-decode` -- [x] `--from-ascii` (with `--from-utf8` alias) -- [x] `--from-bin` -- [x] `--from-fix` -- [x] `--from-wei` -- [x] `--max-int` -- [x] `--max-uint` -- [x] `--min-int` -- [x] `--to-checksum-address` (`--to-address` in dapptools) -- [x] `--to-ascii` -- [x] `--to-bytes32` -- [x] `--to-dec` -- [x] `--to-fix` -- [x] `--to-hex` -- [x] `--to-hexdata` -- [x] `--to-int256` -- [x] `--to-uint256` -- [x] `--to-wei` -- [x] `4byte` -- [x] `4byte-decode` -- [x] `4byte-event` -- [x] `abi-encode` -- [x] `age` -- [x] `balance` -- [x] `basefee` -- [x] `block` -- [x] `block-number` -- [ ] `bundle-source` -- [x] `call` (partial) -- [x] `calldata` -- [x] `chain` -- [x] `chain-id` -- [x] `client` -- [x] `code` -- [ ] `debug` -- [x] `estimate` -- [x] `etherscan-source` -- [ ] `events` -- [x] `gas-price` -- [x] `index` -- [x] `keccak` -- [ ] `logs` -- [x] `lookup-address` -- [ ] `ls` -- [ ] `mktx` -- [x] `namehash` -- [x] `nonce` -- [x] `publish` -- [x] `receipt` -- [x] `resolve-name` -- [ ] `run-tx` -- [x] `send` (partial) -- [x] `sig` -- [ ] `sign` -- [x] `storage` -- [x] `tx` +- [x] `--abi-decode` +- [x] `--calldata-decode` +- [x] `--from-ascii` (with `--from-utf8` alias) +- [x] `--from-bin` +- [x] `--from-fix` +- [x] `--from-wei` +- [x] `--max-int` +- [x] `--max-uint` +- [x] `--min-int` +- [x] `--to-checksum-address` (`--to-address` in dapptools) +- [x] `--to-ascii` +- [x] `--to-bytes32` +- [x] `--to-dec` +- [x] `--to-fix` +- [x] `--to-hex` +- [x] `--to-hexdata` +- [x] `--to-int256` +- [x] `--to-uint256` +- [x] `--to-wei` +- [x] `4byte` +- [x] `4byte-decode` +- [x] `4byte-event` +- [x] `abi-encode` +- [x] `age` +- [x] `balance` +- [x] `basefee` +- [x] `block` +- [x] `block-number` +- [ ] `bundle-source` +- [x] `call` (partial) +- [x] `calldata` +- [x] `chain` +- [x] `chain-id` +- [x] `client` +- [x] `code` +- [ ] `debug` +- [x] `estimate` +- [x] `etherscan-source` +- [ ] `events` +- [x] `gas-price` +- [x] `index` +- [x] `keccak` +- [ ] `logs` +- [x] `lookup-address` +- [ ] `ls` +- [ ] `mktx` +- [x] `namehash` +- [x] `nonce` +- [x] `publish` +- [x] `receipt` +- [x] `resolve-name` +- [ ] `run-tx` +- [x] `send` (partial) +- [x] `sig` +- [ ] `sign` +- [x] `storage` +- [x] `tx` diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 65b20c08626c..80ad68ced722 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -8,11 +8,7 @@ repository = "https://github.com/foundry-rs/foundry" keywords = ["ethereum", "web3"] [build-dependencies] -vergen = { version = "7.0", default-features = false, features = [ - "build", - "rustc", - "git", -] } +vergen = { version = "7.0", default-features = false, features = ["build", "rustc", "git"] } [dependencies] # foundry internal @@ -29,12 +25,7 @@ ethers = { git = "https://github.com/gakonst/ethers-rs", default-features = fals solang-parser = "0.1.11" # cli -clap = { version = "3.0.10", features = [ - "derive", - "env", - "unicode", - "wrap_help", -] } +clap = { version = "3.0.10", features = ["derive", "env", "unicode", "wrap_help"] } clap_complete = "3.0.4" clap_complete_fig = "3.2.4" yansi = "0.5.1" @@ -45,7 +36,11 @@ console = "0.15.0" watchexec = "2.0.0" atty = "0.2.14" comfy-table = "6.0.0" -reqwest = { version = "0.11.8", default-features = false, features = ["json", "rustls", "rustls-native-certs"] } +reqwest = { version = "0.11.8", default-features = false, features = [ + "json", + "rustls", + "rustls-native-certs", +] } dotenv = "0.15.0" dialoguer = { version = "0.10.2", default-features = false } @@ -70,7 +65,7 @@ serde_json = "1.0.67" regex = { version = "1.5.4", default-features = false } rpassword = "7.0.0" hex = "0.4.3" -serde = { version="1.0.133", features = ["derive"] } +serde = { version = "1.0.133", features = ["derive"] } itertools = "0.10.3" proptest = "1.0.0" semver = "1.0.5" diff --git a/cli/README.md b/cli/README.md index d68c006838e3..36464afd1dca 100644 --- a/cli/README.md +++ b/cli/README.md @@ -19,5 +19,4 @@ verbosity level via the environment variable, on a per package level, e.g.:`RUST_LOG=forge,foundry_evm forge test` - -[foundry-book]: https://book.getfoundry.sh \ No newline at end of file +[foundry-book]: https://book.getfoundry.sh diff --git a/cli/test-utils/Cargo.toml b/cli/test-utils/Cargo.toml index c049662127a5..7474ceb49664 100644 --- a/cli/test-utils/Cargo.toml +++ b/cli/test-utils/Cargo.toml @@ -10,7 +10,9 @@ repository = "https://github.com/foundry-rs/foundry" [dependencies] tempfile = "3.3.0" -ethers-solc = { git = "https://github.com/gakonst/ethers-rs", default-features = false, features = ["project-util"] } +ethers-solc = { git = "https://github.com/gakonst/ethers-rs", default-features = false, features = [ + "project-util", +] } ethers = { git = "https://github.com/gakonst/ethers-rs", default-features = false } walkdir = "2.3.2" diff --git a/common/Cargo.toml b/common/Cargo.toml index 8ad3589e4915..e18269d4352d 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -4,9 +4,7 @@ version = "0.1.0" edition = "2021" license = "MIT OR Apache-2.0" readme = "README.md" -description = """ -Common utilities for foundry's tools. -""" +description = "Common utilities for Foundry's tools" repository = "https://github.com/foundry-rs/foundry" [dependencies] @@ -23,19 +21,13 @@ ethers-etherscan = { git = "https://github.com/gakonst/ethers-rs", default-featu reqwest = { version = "0.11", default-features = false } # cli -clap = { version = "3.0.10", features = [ - "derive", - "env", - "unicode", - "wrap_help", -] } +clap = { version = "3.0.10", features = ["derive", "env", "unicode", "wrap_help"] } comfy-table = "6.0.0" tracing = "0.1" atty = "0.2.14" yansi = "0.5.1" tempfile = "3.3.0" - # misc serde = "1.0.133" serde_json = "1.0.67" @@ -48,4 +40,4 @@ dunce = "1.0.2" regex = "1.6.0" [dev-dependencies] -tokio = { version = "1", features = ["rt-multi-thread", "macros"] } \ No newline at end of file +tokio = { version = "1", features = ["rt-multi-thread", "macros"] } diff --git a/common/README.md b/common/README.md index 1d798068b2ac..6f0ed6d555fb 100644 --- a/common/README.md +++ b/common/README.md @@ -1 +1 @@ -Common utilities for building and using foundry's tools. \ No newline at end of file +Common utilities for building and using foundry's tools. diff --git a/config/Cargo.toml b/config/Cargo.toml index 792f95d28d33..a3aa957ec947 100644 --- a/config/Cargo.toml +++ b/config/Cargo.toml @@ -3,16 +3,17 @@ name = "foundry-config" version = "0.2.0" edition = "2021" license = "MIT OR Apache-2.0" -description = """ -Foundry configuration -""" +description = "Foundry configuration" repository = "https://github.com/foundry-rs/foundry" readme = "README.md" [dependencies] # eth ethers-core = { git = "https://github.com/gakonst/ethers-rs", default-features = false } -ethers-solc = { git = "https://github.com/gakonst/ethers-rs", default-features = false, features = ["async", "svm-solc"] } +ethers-solc = { git = "https://github.com/gakonst/ethers-rs", default-features = false, features = [ + "async", + "svm-solc", +] } ethers-etherscan = { git = "https://github.com/gakonst/ethers-rs", default-features = false } # formats diff --git a/docs/dev/README.md b/docs/dev/README.md index 0b6f60ef4042..db7cc3f537c7 100644 --- a/docs/dev/README.md +++ b/docs/dev/README.md @@ -1,6 +1,6 @@ # Contributing Quick Start -The foundry Rust project is organized as a regular [Cargo workspace][cargo-workspace]. +The foundry Rust project is organized as a regular [Cargo workspace][cargo-workspace]. Simply running @@ -21,14 +21,13 @@ See also [Getting Help](../../README.md#getting-help) # Issue Labels -* [good-first-issue](https://github.com/foundry-rs/foundry/labels/good%20first%20issue) - are good issues to get into the project. -* [D-easy](https://github.com/foundry-rs/foundry/issues?q=is%3Aopen+is%3Aissue+label%3AD-easy), - [D-average](https://github.com/foundry-rs/foundry/issues?q=is%3Aopen+is%3Aissue+label%3AD-medium), - [D-hard](https://github.com/foundry-rs/foundry/issues?q=is%3Aopen+is%3Aissue+label%3AD-hard), - [D-chore](https://github.com/foundry-rs/foundry/issues?q=is%3Aopen+is%3Aissue+label%3AD-chore), - labels indicate how hard it would be to write a fix or add a feature. - +- [good-first-issue](https://github.com/foundry-rs/foundry/labels/good%20first%20issue) + are good issues to get into the project. +- [D-easy](https://github.com/foundry-rs/foundry/issues?q=is%3Aopen+is%3Aissue+label%3AD-easy), + [D-average](https://github.com/foundry-rs/foundry/issues?q=is%3Aopen+is%3Aissue+label%3AD-medium), + [D-hard](https://github.com/foundry-rs/foundry/issues?q=is%3Aopen+is%3Aissue+label%3AD-hard), + [D-chore](https://github.com/foundry-rs/foundry/issues?q=is%3Aopen+is%3Aissue+label%3AD-chore), + labels indicate how hard it would be to write a fix or add a feature. # CI @@ -37,8 +36,8 @@ We use [cargo-nextest][nextest] as the test runner If `cargo test` passes locally, that's a good sign that CI will be green as well. We also have tests that make use of forking mode which can be long running if the required state is not already cached locally. Forking-related tests are executed exclusively in a separate CI job, they are identified by `fork` in their name. -So all of them can be easily skipped by `cargo t -- --skip fork` +So all of them can be easily skipped by `cargo t -- --skip fork` [foundry-book]: https://book.getfoundry.sh [cargo-workspace]: https://doc.rust-lang.org/book/ch14-03-cargo-workspaces.html -[nextest]: https://nexte.st/ \ No newline at end of file +[nextest]: https://nexte.st/ diff --git a/docs/dev/architecture.md b/docs/dev/architecture.md index d30fdcd7ed98..4e1f3bb5e543 100644 --- a/docs/dev/architecture.md +++ b/docs/dev/architecture.md @@ -7,8 +7,8 @@ This document describes the high-level architecture of foundry. foundry's evm tooling. This is built around [`revm`](https://github.com/bluealloy/revm) and has additional implementation of -* [cheatcodes](./cheatcodes.md) a set of solidity calls dedicated to testing which can manipulate the environment in - which the execution is run +- [cheatcodes](./cheatcodes.md) a set of solidity calls dedicated to testing which can manipulate the environment in + which the execution is run ### `config/` @@ -16,4 +16,4 @@ Includes all of foundry's settings and how to get them ### `cli/` -The core `forge` and `cast` cli implementation. Includes all subcommands. \ No newline at end of file +The core `forge` and `cast` cli implementation. Includes all subcommands. diff --git a/docs/dev/cheatcodes.md b/docs/dev/cheatcodes.md index 6939c0b09bc5..1b95f6364c10 100644 --- a/docs/dev/cheatcodes.md +++ b/docs/dev/cheatcodes.md @@ -27,10 +27,10 @@ For example `Inspector::call` is called wen the EVM is about to execute a call: the `evm` crate has a variety of inspectors for different use cases, such as -* coverage -* tracing -* debugger -* cheat codes + logging +- coverage +- tracing +- debugger +- cheat codes + logging ## [Cheat code Inspector](../../evm/src/executor/inspector/cheatcodes) @@ -89,4 +89,4 @@ This process consists of 4 steps: 2. implement the cheat code handler 3. add a Solidity test for the cheatcode under [`testdata/cheats`](https://github.com/foundry-rs/foundry/tree/master/testdata/cheats) 4. add the function signature - to [forge-std Vm interface](https://github.com/foundry-rs/forge-std/blob/master/src/Vm.sol) \ No newline at end of file + to [forge-std Vm interface](https://github.com/foundry-rs/forge-std/blob/master/src/Vm.sol) diff --git a/docs/dev/debugging.md b/docs/dev/debugging.md index 034364809db4..15281efecd9c 100644 --- a/docs/dev/debugging.md +++ b/docs/dev/debugging.md @@ -10,11 +10,11 @@ By setting `RUST_LOG=` you can get a lot more info out of Forge and Cast The most basic valid filter is a log level, of which these are valid: -- `error` -- `warn` -- `info` -- `debug` -- `trace` +- `error` +- `warn` +- `info` +- `debug` +- `trace` Filters are explained in detail in the [`env_logger` crate docs](https://docs.rs/env_logger). diff --git a/evm/Cargo.toml b/evm/Cargo.toml index b782d4c62c88..6e2c2ef291f2 100644 --- a/evm/Cargo.toml +++ b/evm/Cargo.toml @@ -16,7 +16,10 @@ foundry-config = { path = "./../config" } serde_json = "1.0.67" serde = "1.0.130" hex = "0.4.3" -ethers = { git = "https://github.com/gakonst/ethers-rs", default-features = false, features = ["solc-full", "abigen"] } +ethers = { git = "https://github.com/gakonst/ethers-rs", default-features = false, features = [ + "solc-full", + "abigen", +] } jsonpath-rust = "0.1.5" # Error handling @@ -36,7 +39,12 @@ once_cell = "1.13" # EVM bytes = "1.1.0" hashbrown = { version = "0.12", features = ["serde"] } -revm = { version = "2.1", default-features = false, features = ["std", "k256", "with-serde", "memory_limit"] } +revm = { version = "2.1", default-features = false, features = [ + "std", + "k256", + "with-serde", + "memory_limit", +] } # Fuzzer proptest = "1.0.0" diff --git a/fmt/Cargo.toml b/fmt/Cargo.toml index d86c5f43e82d..c4c2fb91bb0d 100644 --- a/fmt/Cargo.toml +++ b/fmt/Cargo.toml @@ -2,9 +2,7 @@ name = "forge-fmt" version = "0.2.0" edition = "2021" -description = """ -Foundry's solidity formatting and linting support -""" +description = "Foundry's solidity formatting and linting support" license = "MIT OR Apache-2.0" readme = "README.md" repository = "https://github.com/foundry-rs/foundry" diff --git a/fmt/README.md b/fmt/README.md index 2b08635f0d61..ebae9b04bfcf 100644 --- a/fmt/README.md +++ b/fmt/README.md @@ -6,15 +6,17 @@ is tested on the [Prettier Solidity Plugin](https://github.com/prettier-solidity ## Architecture The formatter works in two steps: + 1. Parse Solidity source code with [solang](https://github.com/hyperledger-labs/solang) into the PT (Parse Tree) -(not the same as Abstract Syntax Tree, [see difference](https://stackoverflow.com/a/9864571)). + (not the same as Abstract Syntax Tree, [see difference](https://stackoverflow.com/a/9864571)). 2. Walk the PT and output new source code that's compliant with provided config and rule set. The technique for walking the tree is based on [Visitor Pattern](https://en.wikipedia.org/wiki/Visitor_pattern) and works as following: + 1. Implement `Formatter` callback functions for each PT node type. -Every callback function should write formatted output for the current node -and call `Visitable::visit` function for child nodes delegating the output writing. + Every callback function should write formatted output for the current node + and call `Visitable::visit` function for child nodes delegating the output writing. 1. Implement `Visitable` trait and its `visit` function for each PT node type. Every `visit` function should call corresponding `Formatter`'s callback function. ### Output @@ -61,6 +63,7 @@ comments also get written. ### Example Source code + ```solidity pragma solidity ^0.8.10 ; contract HelloWorld { @@ -73,6 +76,7 @@ event Greet( string indexed name) ; ``` Parse Tree (simplified) + ```text SourceUnit | PragmaDirective("solidity", "^0.8.10") @@ -84,6 +88,7 @@ SourceUnit ``` Formatted source code that was reconstructed from the Parse Tree + ```solidity pragma solidity ^0.8.10; @@ -102,15 +107,16 @@ event Greet(string indexed name); Formatter supports multiple configuration options defined in `FormatterConfig`. -| Option | Default | Description -| --------------------------------- | ------- | --------------------- -| line_length | 120 | Maximum line length where formatter will try to wrap the line -| tab_width | 4 | Number of spaces per indentation level -| bracket_spacing | false | Print spaces between brackets -| int_types | long | Style of uint/int256 types. Available options: `long`, `short`, `preserve` -| func_attrs_with_params_multiline | true | If function parameters are multiline then always put the function attributes on separate lines -| quote_style | double | Style of quotation marks. Available options: `double`, `single`, `preserve` -| number_underscore | preserve | Style of underscores in number literals. Available options: `remove`, `thousands`, `preserve` +| Option | Default | Description | +| -------------------------------- | -------- | ---------------------------------------------------------------------------------------------- | +| line_length | 120 | Maximum line length where formatter will try to wrap the line | +| tab_width | 4 | Number of spaces per indentation level | +| bracket_spacing | false | Print spaces between brackets | +| int_types | long | Style of uint/int256 types. Available options: `long`, `short`, `preserve` | +| func_attrs_with_params_multiline | true | If function parameters are multiline then always put the function attributes on separate lines | +| quote_style | double | Style of quotation marks. Available options: `double`, `single`, `preserve` | +| number_underscore | preserve | Style of underscores in number literals. Available options: `remove`, `thousands`, `preserve` | + TODO: update ^ ### Testing @@ -118,11 +124,13 @@ TODO: update ^ Tests reside under `fmt/testdata` folder and specify the malformated & expected Solidity code. The source code file is named `original.sol` and expected file(s) are named in a format `({prefix}.)?fmt.sol`. Multiple expected files are needed for tests covering available configuration options. The default configuration values can be overriden from within the expected file by adding a comment in the format `// config: {config_entry} = {config_value}`. For example: + ```solidity // config: line_length = 160 ``` The `test_directory` macro is used to specify a new folder with source files for the test suite. Each test suite has the following process: + 1. Preparse comments with config values 2. Parse and compare the AST for source & expected files. - The `AstEq` trait defines the comparison rules for the AST nodes diff --git a/forge/Cargo.toml b/forge/Cargo.toml index 733f775619a7..05954d92dcf0 100644 --- a/forge/Cargo.toml +++ b/forge/Cargo.toml @@ -10,7 +10,9 @@ foundry-common = { path = "./../common" } foundry-config = { path = "./../config" } foundry-evm = { path = "./../evm" } -ethers = { git = "https://github.com/gakonst/ethers-rs", default-features = false, features = ["solc-full"] } +ethers = { git = "https://github.com/gakonst/ethers-rs", default-features = false, features = [ + "solc-full", +] } eyre = "0.6.5" semver = "1.0.5" serde_json = "1.0.67" @@ -31,6 +33,8 @@ comfy-table = "6.0.0" parking_lot = "0.12" [dev-dependencies] -ethers = { git = "https://github.com/gakonst/ethers-rs", default-features = false, features = ["solc-full", "solc-tests"] } +ethers = { git = "https://github.com/gakonst/ethers-rs", default-features = false, features = [ + "solc-full", + "solc-tests", +] } foundry-utils = { path = "./../utils", features = ["test"] } - diff --git a/forge/README.md b/forge/README.md index 5b1daa1afded..60cdc75f24a5 100644 --- a/forge/README.md +++ b/forge/README.md @@ -72,37 +72,37 @@ function testDoubleWithFuzzing(uint256 x) public { ## Features -- [ ] test - - [x] Simple unit tests - - [x] Gas costs - - [x] DappTools style test output - - [x] JSON test output - - [x] Matching on regex - - [x] DSTest-style assertions support - - [x] Fuzzing - - [ ] Symbolic execution - - [ ] Coverage - - [x] HEVM-style Solidity cheatcodes - - [ ] Structured tracing with abi decoding - - [ ] Per-line gas profiling - - [x] Forking mode - - [x] Automatic solc selection -- [x] build - - [x] Can read DappTools-style .sol.json artifacts - - [x] Manual remappings - - [x] Automatic remappings - - [x] Multiple compiler versions - - [x] Incremental compilation - - [ ] Can read Hardhat-style artifacts - - [ ] Can read Truffle-style artifacts -- [x] install -- [x] update -- [ ] debug -- [x] CLI Tracing with `RUST_LOG=forge=trace` +- [ ] test + - [x] Simple unit tests + - [x] Gas costs + - [x] DappTools style test output + - [x] JSON test output + - [x] Matching on regex + - [x] DSTest-style assertions support + - [x] Fuzzing + - [ ] Symbolic execution + - [ ] Coverage + - [x] HEVM-style Solidity cheatcodes + - [ ] Structured tracing with abi decoding + - [ ] Per-line gas profiling + - [x] Forking mode + - [x] Automatic solc selection +- [x] build + - [x] Can read DappTools-style .sol.json artifacts + - [x] Manual remappings + - [x] Automatic remappings + - [x] Multiple compiler versions + - [x] Incremental compilation + - [ ] Can read Hardhat-style artifacts + - [ ] Can read Truffle-style artifacts +- [x] install +- [x] update +- [ ] debug +- [x] CLI Tracing with `RUST_LOG=forge=trace` ### Gas Report -Foundry will show you a comprehensive gas report about your contracts. It returns the `min`, `average`, `median` and, `max` gas cost for every function. +Foundry will show you a comprehensive gas report about your contracts. It returns the `min`, `average`, `median` and, `max` gas cost for every function. It looks at **all** the tests that make a call to a given function and records the associated gas costs. For example, if something calls a function and it reverts, that's probably the `min` value. Another example is the `max` value that is generated usually during the first call of the function (as it has to initialise storage, variables, etc.) @@ -110,7 +110,6 @@ Usually, the `median` value is what your users will probably end up paying. `max image - ### Cheat codes _The below is modified from @@ -120,68 +119,67 @@ We allow modifying blockchain state with "cheat codes". These can be accessed by calling into a contract at address `0x7109709ECfa91a80626fF3989D68f67F5b1DD12D`, which implements the following methods: -- `function warp(uint x) public` Sets the block timestamp to `x`. +- `function warp(uint x) public` Sets the block timestamp to `x`. -- `function difficulty(uint x) public` Sets the block difficulty to `x`. +- `function difficulty(uint x) public` Sets the block difficulty to `x`. -- `function roll(uint x) public` Sets the block number to `x`. +- `function roll(uint x) public` Sets the block number to `x`. -- `function coinbase(address c) public` Sets the block coinbase to `c`. +- `function coinbase(address c) public` Sets the block coinbase to `c`. -- `function store(address c, bytes32 loc, bytes32 val) public` Sets the slot - `loc` of contract `c` to `val`. +- `function store(address c, bytes32 loc, bytes32 val) public` Sets the slot + `loc` of contract `c` to `val`. -- `function load(address c, bytes32 loc) public returns (bytes32 val)` Reads the - slot `loc` of contract `c`. +- `function load(address c, bytes32 loc) public returns (bytes32 val)` Reads the + slot `loc` of contract `c`. -- `function sign(uint sk, bytes32 digest) public returns (uint8 v, bytes32 r, bytes32 s)` - Signs the `digest` using the private key `sk`. Note that signatures produced - via `hevm.sign` will leak the private key. +- `function sign(uint sk, bytes32 digest) public returns (uint8 v, bytes32 r, bytes32 s)` + Signs the `digest` using the private key `sk`. Note that signatures produced + via `hevm.sign` will leak the private key. -- `function addr(uint sk) public returns (address addr)` Derives an ethereum - address from the private key `sk`. Note that `hevm.addr(0)` will fail with - `BadCheatCode` as `0` is an invalid ECDSA private key. `sk` values above the - secp256k1 curve order, near the max uint256 value will also fail. +- `function addr(uint sk) public returns (address addr)` Derives an ethereum + address from the private key `sk`. Note that `hevm.addr(0)` will fail with + `BadCheatCode` as `0` is an invalid ECDSA private key. `sk` values above the + secp256k1 curve order, near the max uint256 value will also fail. -- `function ffi(string[] calldata) external returns (bytes memory)` Executes the - arguments as a command in the system shell and returns stdout. Note that this - cheatcode means test authors can execute arbitrary code on user machines as - part of a call to `forge test`, for this reason all calls to `ffi` will fail - unless the `--ffi` flag is passed. +- `function ffi(string[] calldata) external returns (bytes memory)` Executes the + arguments as a command in the system shell and returns stdout. Note that this + cheatcode means test authors can execute arbitrary code on user machines as + part of a call to `forge test`, for this reason all calls to `ffi` will fail + unless the `--ffi` flag is passed. -- `function deal(address who, uint256 amount)`: Sets an account's balance +- `function deal(address who, uint256 amount)`: Sets an account's balance -- `function etch(address where, bytes memory what)`: Sets the contract code at - some address contract code +- `function etch(address where, bytes memory what)`: Sets the contract code at + some address contract code -- `function prank(address sender)`: Performs the next smart contract call as another address (prank just changes msg.sender. Tx still occurs as normal) +- `function prank(address sender)`: Performs the next smart contract call as another address (prank just changes msg.sender. Tx still occurs as normal) -- `function prank(address sender, address origin)`: Performs the next smart contract call setting both `msg.sender` and `tx.origin`. +- `function prank(address sender, address origin)`: Performs the next smart contract call setting both `msg.sender` and `tx.origin`. -- `function startPrank(address sender)`: Performs smart contract calls as another address. The account impersonation lasts until the end of the transaction, or until `stopPrank` is called. +- `function startPrank(address sender)`: Performs smart contract calls as another address. The account impersonation lasts until the end of the transaction, or until `stopPrank` is called. -- `function startPrank(address sender, address origin)`: Performs smart contract calls as another address, while also setting `tx.origin`. The account impersonation lasts until the end of the transaction, or until `stopPrank` is called. +- `function startPrank(address sender, address origin)`: Performs smart contract calls as another address, while also setting `tx.origin`. The account impersonation lasts until the end of the transaction, or until `stopPrank` is called. -- `function stopPrank()`: Stop calling smart contracts with the address set at `startPrank` +- `function stopPrank()`: Stop calling smart contracts with the address set at `startPrank` -- `function expectRevert( expectedError)`: - Tells the evm to expect that the next call reverts with specified error bytes. Valid input types: `bytes`, and `bytes4`. Implicitly, strings get converted to bytes except when shorter than 4, in which case you will need to cast explicitly to `bytes`. - -- `function expectEmit(bool,bool,bool,bool) external`: Expects the next emitted event. Params check topic 1, topic 2, topic 3 and data are the same. +- `function expectRevert( expectedError)`: + Tells the evm to expect that the next call reverts with specified error bytes. Valid input types: `bytes`, and `bytes4`. Implicitly, strings get converted to bytes except when shorter than 4, in which case you will need to cast explicitly to `bytes`. +- `function expectEmit(bool,bool,bool,bool) external`: Expects the next emitted event. Params check topic 1, topic 2, topic 3 and data are the same. -- `function expectEmit(bool,bool,bool,bool,address) external`: Expects the next emitted event. Params check topic 1, topic 2, topic 3 and data are the same. Also checks supplied address against address of originating contract. +- `function expectEmit(bool,bool,bool,bool,address) external`: Expects the next emitted event. Params check topic 1, topic 2, topic 3 and data are the same. Also checks supplied address against address of originating contract. -- `function getCode(string calldata) external returns (bytes memory)`: Fetches bytecode from a contract artifact. The parameter can either be in the form `ContractFile.sol` (if the filename and contract name are the same), `ContractFile.sol:ContractName`, or `./path/to/artifact.json`. +- `function getCode(string calldata) external returns (bytes memory)`: Fetches bytecode from a contract artifact. The parameter can either be in the form `ContractFile.sol` (if the filename and contract name are the same), `ContractFile.sol:ContractName`, or `./path/to/artifact.json`. -- `function label(address addr, string calldata label) external`: Label an address in test traces. +- `function label(address addr, string calldata label) external`: Label an address in test traces. -- `function assume(bool) external`: When fuzzing, generate new inputs if conditional not met +- `function assume(bool) external`: When fuzzing, generate new inputs if conditional not met -- `function setNonce(address account, uint64 nonce) external`: Set nonce for an account, increment only. +- `function setNonce(address account, uint64 nonce) external`: Set nonce for an account, increment only. -- `function getNonce(address account)`: Get nonce for an account. +- `function getNonce(address account)`: Get nonce for an account. -- `function chainId(uint x) public` Sets the block chainid to `x`. +- `function chainId(uint x) public` Sets the block chainid to `x`. The below example uses the `warp` cheatcode to override the timestamp & `expectRevert` to expect a specific revert string: @@ -238,7 +236,7 @@ contract T is DSTest { emit Transfer(address(this), address(1337), 1337); emitter.t(); } - + function testExpectEmitWithAddress() public { ExpectEmit emitter = new ExpectEmit(); // do the same as above and check emitting address @@ -257,6 +255,7 @@ contract ExpectEmit { ``` A full interface for all cheatcodes is here: + ```solidity interface Hevm { // Set block.timestamp (newTimestamp) @@ -330,8 +329,8 @@ interface Hevm { function getNonce(address) external returns(uint64); } ``` -### `console.log` +### `console.log` We support the logging functionality from Hardhat's `console.log`. @@ -340,6 +339,7 @@ If you are on a hardhat project, `import hardhat/console.sol` should just work i If no, there is an implementation contract [here](https://raw.githubusercontent.com/NomicFoundation/hardhat/master/packages/hardhat-core/console.sol). We currently recommend that you copy this contract, place it in your `test` folder, and import it into the contract where you wish to use `console.log`, though there should be more streamlined functionality soon. Usage follows the same format as [Hardhat](https://hardhat.org/hardhat-network/reference/#console-log): + ```solidity import "./console.sol"; ... @@ -348,6 +348,7 @@ console.log(someValue); ``` Note: to make logs visible in `stdout`, you must use at least level 2 verbosity. + ```bash $> forge test -vv [PASS] test1() (gas: 7683) @@ -358,18 +359,21 @@ Logs: ``` ## Remappings + If you are working in a repo with NPM-style imports, like + ``` import "@openzeppelin/contracts/access/Ownable.sol"; ``` -then you will need to create a `remappings.txt` file at the top level of your project directory, so that Forge knows where to find these dependencies. +then you will need to create a `remappings.txt` file at the top level of your project directory, so that Forge knows where to find these dependencies. -For example, if you have `@openzeppelin` imports, you would +For example, if you have `@openzeppelin` imports, you would 1. `forge install openzeppelin/openzeppelin-contracts` (this will add the repo to `lib/openzepplin-contracts`) 2. Create a remappings file: `touch remappings.txt` -3. Add this line to `remappings.txt` +3. Add this line to `remappings.txt` + ``` @openzeppelin/=lib/openzeppelin-contracts/ ``` @@ -403,16 +407,16 @@ We also intend to add features which are not available in dapptools: 1. Even faster tests with parallel EVM execution that produces state diffs instead of modifying the state 1. Improved UX for assertions: - 1. Check revert error or reason on a Solidity call - 1. Check that an event was emitted with expected arguments + 1. Check revert error or reason on a Solidity call + 1. Check that an event was emitted with expected arguments 1. Support more EVM backends ([revm](https://github.com/bluealloy/revm/), geth's evm, hevm etc.) & benchmark performance across them 1. Declarative deployment system based on a config file 1. Formatting & Linting (maybe powered by [Solang](https://github.com/hyperledger-labs/solang)) - 1. `forge fmt`, an automatic code formatter according to standard rules (like - [`prettier-plugin-solidity`](https://github.com/prettier-solidity/prettier-plugin-solidity)) - 1. `forge lint`, a linter + static analyzer, like a combination of - [`solhint`](https://github.com/protofire/solhint) and - [slither](https://github.com/crytic/slither/) + 1. `forge fmt`, an automatic code formatter according to standard rules (like + [`prettier-plugin-solidity`](https://github.com/prettier-solidity/prettier-plugin-solidity)) + 1. `forge lint`, a linter + static analyzer, like a combination of + [`solhint`](https://github.com/protofire/solhint) and + [slither](https://github.com/crytic/slither/) 1. Flamegraphs for gas profiling diff --git a/foundryup/README.md b/foundryup/README.md index 9e9e783a4433..39a53288c001 100644 --- a/foundryup/README.md +++ b/foundryup/README.md @@ -47,12 +47,14 @@ foundryup --pr 1071 ``` To install from a **specific commit**: + ```sh foundryup -C 94bfdb2 ``` To install a local directory or repository (e.g. one located at `~/git/foundry`, assuming you're in the home directory) -##### Note: --branch, --repo, and --version flags are ignored during local installations. + +##### Note: --branch, --repo, and --version flags are ignored during local installations. ```sh foundryup --path ./git/foundry diff --git a/foundryup/foundryup b/foundryup/foundryup index b06c5d1d45ea..4672572451e7 100755 --- a/foundryup/foundryup +++ b/foundryup/foundryup @@ -23,7 +23,7 @@ main() { usage exit 0 ;; - *) + *) err "internal error: unknown option "$1"\n";; esac; shift done @@ -132,11 +132,11 @@ main() { say "installed - $($FOUNDRY_BIN_DIR/cast --version)" say "installed - $($FOUNDRY_BIN_DIR/anvil --version)" say "done" - + if [[ $(which forge) =~ "cargo" ]]; then warn "it appears your system has already has forge installed via cargo. you may need to run 'rm $(which forge)' to allow foundryup to take precedence!" fi - + if [[ $(which cast) =~ "cargo" ]]; then warn "it appears your system has already has cast installed via cargo. you may need to run 'rm $(which cast)' to allow foundryup to take precedence!" fi diff --git a/rustfmt.toml b/rustfmt.toml index 8971d8abc0d4..e70aee8ccf56 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -6,4 +6,4 @@ wrap_comments = true binop_separator = "Back" trailing_comma = "Vertical" trailing_semicolon = false -use_field_init_shorthand = true \ No newline at end of file +use_field_init_shorthand = true diff --git a/testdata/README.md b/testdata/README.md index 770a8b0de07c..566da52d136f 100644 --- a/testdata/README.md +++ b/testdata/README.md @@ -4,9 +4,9 @@ A test suite that tests different aspects of Foundry. ### Structure -- [`core`](core): Tests for fundamental aspects of Foundry -- [`logs`](logs): Tests for Foundry logging capabilities -- [`cheats`](cheats): Tests for Foundry cheatcodes -- [`fuzz`](fuzz): Tests for the Foundry fuzzer -- [`trace`](trace): Tests for the Foundry tracer -- [`fork`](fork): Tests for Foundry forking capabilities +- [`core`](core): Tests for fundamental aspects of Foundry +- [`logs`](logs): Tests for Foundry logging capabilities +- [`cheats`](cheats): Tests for Foundry cheatcodes +- [`fuzz`](fuzz): Tests for the Foundry fuzzer +- [`trace`](trace): Tests for the Foundry tracer +- [`fork`](fork): Tests for Foundry forking capabilities diff --git a/testdata/foundry.toml b/testdata/foundry.toml index 8f9f83e56bd0..43033cdbd791 100644 --- a/testdata/foundry.toml +++ b/testdata/foundry.toml @@ -28,7 +28,7 @@ offline = false optimizer = true optimizer_runs = 200 out = 'out' -remappings = ['ds-test/=lib/ds-test/src/','forge-std/=lib/forge-std/src/'] +remappings = ['ds-test/=lib/ds-test/src/', 'forge-std/=lib/forge-std/src/'] sender = '0x00a329c0648769a73afac7f9381e08fb43dbea72' sizes = false sparse_mode = false diff --git a/utils/Cargo.toml b/utils/Cargo.toml index 8157eb353a3d..b3505f166529 100644 --- a/utils/Cargo.toml +++ b/utils/Cargo.toml @@ -8,12 +8,17 @@ repository = "https://github.com/foundry-rs/foundry" [dependencies] ethers-core = { git = "https://github.com/gakonst/ethers-rs", default-features = false } -ethers-contract = { git = "https://github.com/gakonst/ethers-rs", default-features = false, features = ["abigen"] } +ethers-contract = { git = "https://github.com/gakonst/ethers-rs", default-features = false, features = [ + "abigen", +] } ethers-etherscan = { git = "https://github.com/gakonst/ethers-rs", default-features = false } ethers-addressbook = { git = "https://github.com/gakonst/ethers-rs", default-features = false } ethers-providers = { git = "https://github.com/gakonst/ethers-rs", default-features = false } ethers-solc = { git = "https://github.com/gakonst/ethers-rs", default-features = false } -tracing-subscriber = { version = "0.3", default-features = false, features = ["env-filter", "fmt"], optional = true } +tracing-subscriber = { version = "0.3", default-features = false, features = [ + "env-filter", + "fmt", +], optional = true } forge-fmt = { path = "../fmt" } @@ -31,9 +36,10 @@ once_cell = "1.13" rand = "0.8" [dev-dependencies] -foundry-common = {path = "./../common"} -ethers = { git = "https://github.com/gakonst/ethers-rs", default-features = false, features = ["solc-full"] } - +foundry-common = { path = "./../common" } +ethers = { git = "https://github.com/gakonst/ethers-rs", default-features = false, features = [ + "solc-full", +] } [features] test = ["tracing-subscriber"]